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/output/context_provider.h"
10 #include "cc/output/output_surface.h"
11 #include "cc/quads/draw_quad.h"
12 #include "cc/resources/prioritized_resource_manager.h"
13 #include "cc/resources/resource_update_controller.h"
14 #include "cc/trees/blocking_task_runner.h"
15 #include "cc/trees/layer_tree_host.h"
16 #include "cc/trees/layer_tree_impl.h"
20 scoped_ptr
<Proxy
> SingleThreadProxy::Create(LayerTreeHost
* layer_tree_host
) {
21 return make_scoped_ptr(
22 new SingleThreadProxy(layer_tree_host
)).PassAs
<Proxy
>();
25 SingleThreadProxy::SingleThreadProxy(LayerTreeHost
* layer_tree_host
)
27 layer_tree_host_(layer_tree_host
),
28 created_offscreen_context_provider_(false),
29 next_frame_is_newly_committed_frame_(false),
31 TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
32 DCHECK(Proxy::IsMainThread());
33 DCHECK(layer_tree_host
);
35 // Impl-side painting not supported without threaded compositing.
36 CHECK(!layer_tree_host
->settings().impl_side_painting
)
37 << "Threaded compositing must be enabled to use impl-side painting.";
40 void SingleThreadProxy::Start(scoped_ptr
<OutputSurface
> first_output_surface
) {
41 DCHECK(first_output_surface
);
42 DebugScopedSetImplThread
impl(this);
43 layer_tree_host_impl_
= layer_tree_host_
->CreateLayerTreeHostImpl(this);
44 first_output_surface_
= first_output_surface
.Pass();
47 SingleThreadProxy::~SingleThreadProxy() {
48 TRACE_EVENT0("cc", "SingleThreadProxy::~SingleThreadProxy");
49 DCHECK(Proxy::IsMainThread());
50 // Make sure Stop() got called or never Started.
51 DCHECK(!layer_tree_host_impl_
);
54 bool SingleThreadProxy::CompositeAndReadback(void* pixels
, gfx::Rect rect
) {
55 TRACE_EVENT0("cc", "SingleThreadProxy::CompositeAndReadback");
56 DCHECK(Proxy::IsMainThread());
58 gfx::Rect device_viewport_damage_rect
= rect
;
60 LayerTreeHostImpl::FrameData frame
;
61 if (!CommitAndComposite(base::TimeTicks::Now(),
62 device_viewport_damage_rect
,
68 DebugScopedSetImplThread
impl(this);
69 layer_tree_host_impl_
->Readback(pixels
, rect
);
71 if (layer_tree_host_impl_
->IsContextLost())
78 void SingleThreadProxy::FinishAllRendering() {
79 DCHECK(Proxy::IsMainThread());
81 DebugScopedSetImplThread
impl(this);
82 layer_tree_host_impl_
->FinishAllRendering();
86 bool SingleThreadProxy::IsStarted() const {
87 DCHECK(Proxy::IsMainThread());
88 return layer_tree_host_impl_
;
91 void SingleThreadProxy::SetLayerTreeHostClientReady() {
92 // Scheduling is controlled by the embedder in the single thread case, so
96 void SingleThreadProxy::SetVisible(bool visible
) {
97 DebugScopedSetImplThread
impl(this);
98 layer_tree_host_impl_
->SetVisible(visible
);
100 // Changing visibility could change ShouldComposite().
101 UpdateBackgroundAnimateTicking();
104 void SingleThreadProxy::CreateAndInitializeOutputSurface() {
106 "cc", "SingleThreadProxy::CreateAndInitializeOutputSurface");
107 DCHECK(Proxy::IsMainThread());
109 scoped_ptr
<OutputSurface
> output_surface
= first_output_surface_
.Pass();
111 output_surface
= layer_tree_host_
->CreateOutputSurface();
112 if (!output_surface
) {
113 OnOutputSurfaceInitializeAttempted(false);
117 scoped_refptr
<cc::ContextProvider
> offscreen_context_provider
;
118 if (created_offscreen_context_provider_
) {
119 offscreen_context_provider
=
120 layer_tree_host_
->client()->OffscreenContextProviderForMainThread();
121 if (!offscreen_context_provider
.get()) {
122 OnOutputSurfaceInitializeAttempted(false);
128 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
129 DebugScopedSetImplThread
impl(this);
130 layer_tree_host_
->DeleteContentsTexturesOnImplThread(
131 layer_tree_host_impl_
->resource_provider());
136 DebugScopedSetImplThread
impl(this);
138 DCHECK(output_surface
);
139 initialized
= layer_tree_host_impl_
->InitializeRenderer(
140 output_surface
.Pass());
142 renderer_capabilities_for_main_thread_
=
143 layer_tree_host_impl_
->GetRendererCapabilities();
144 } else if (offscreen_context_provider
.get()) {
145 offscreen_context_provider
->VerifyContexts();
146 offscreen_context_provider
= NULL
;
149 layer_tree_host_impl_
->SetOffscreenContextProvider(
150 offscreen_context_provider
);
153 OnOutputSurfaceInitializeAttempted(initialized
);
156 void SingleThreadProxy::OnOutputSurfaceInitializeAttempted(bool success
) {
157 LayerTreeHost::CreateResult result
=
158 layer_tree_host_
->OnCreateAndInitializeOutputSurfaceAttempted(success
);
159 if (result
== LayerTreeHost::CreateFailedButTryAgain
) {
160 // Force another recreation attempt to happen by requesting another commit.
165 const RendererCapabilities
& SingleThreadProxy::GetRendererCapabilities() const {
166 DCHECK(Proxy::IsMainThread());
167 DCHECK(!layer_tree_host_
->output_surface_lost());
168 return renderer_capabilities_for_main_thread_
;
171 void SingleThreadProxy::SetNeedsAnimate() {
172 // Thread-only feature.
176 void SingleThreadProxy::SetNeedsUpdateLayers() {
177 DCHECK(Proxy::IsMainThread());
178 layer_tree_host_
->ScheduleComposite();
181 void SingleThreadProxy::DoCommit(scoped_ptr
<ResourceUpdateQueue
> queue
) {
182 DCHECK(Proxy::IsMainThread());
183 // Commit immediately.
185 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
186 DebugScopedSetImplThread
impl(this);
188 // This CapturePostTasks should be destroyed before CommitComplete() is
189 // called since that goes out to the embedder, and we want the embedder
190 // to receive its callbacks before that.
191 BlockingTaskRunner::CapturePostTasks blocked
;
193 RenderingStatsInstrumentation
* stats_instrumentation
=
194 layer_tree_host_
->rendering_stats_instrumentation();
195 base::TimeTicks start_time
= stats_instrumentation
->StartRecording();
197 layer_tree_host_impl_
->BeginCommit();
199 if (layer_tree_host_
->contents_texture_manager()) {
200 layer_tree_host_
->contents_texture_manager()->
201 PushTexturePrioritiesToBackings();
203 layer_tree_host_
->BeginCommitOnImplThread(layer_tree_host_impl_
.get());
205 scoped_ptr
<ResourceUpdateController
> update_controller
=
206 ResourceUpdateController::Create(
208 Proxy::MainThreadTaskRunner(),
210 layer_tree_host_impl_
->resource_provider());
211 update_controller
->Finalize();
213 if (layer_tree_host_impl_
->EvictedUIResourcesExist())
214 layer_tree_host_
->RecreateUIResources();
216 layer_tree_host_
->FinishCommitOnImplThread(layer_tree_host_impl_
.get());
218 layer_tree_host_impl_
->CommitComplete();
221 // In the single-threaded case, the scale and scroll deltas should never be
222 // touched on the impl layer tree.
223 scoped_ptr
<ScrollAndScaleSet
> scroll_info
=
224 layer_tree_host_impl_
->ProcessScrollDeltas();
225 DCHECK(!scroll_info
->scrolls
.size());
226 DCHECK_EQ(1.f
, scroll_info
->page_scale_delta
);
229 base::TimeDelta duration
= stats_instrumentation
->EndRecording(start_time
);
230 stats_instrumentation
->AddCommit(duration
);
231 stats_instrumentation
->IssueTraceEventForMainThreadStats();
232 stats_instrumentation
->AccumulateAndClearMainThreadStats();
234 layer_tree_host_
->CommitComplete();
235 next_frame_is_newly_committed_frame_
= true;
238 void SingleThreadProxy::SetNeedsCommit() {
239 DCHECK(Proxy::IsMainThread());
240 layer_tree_host_
->ScheduleComposite();
243 void SingleThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect
) {
244 SetNeedsRedrawRectOnImplThread(damage_rect
);
247 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
248 // There is no activation here other than commit. So do nothing.
251 void SingleThreadProxy::SetDeferCommits(bool defer_commits
) {
252 // Thread-only feature.
256 bool SingleThreadProxy::CommitRequested() const { return false; }
258 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
259 return std::numeric_limits
<size_t>::max();
262 void SingleThreadProxy::Stop() {
263 TRACE_EVENT0("cc", "SingleThreadProxy::stop");
264 DCHECK(Proxy::IsMainThread());
266 DebugScopedSetMainThreadBlocked
mainThreadBlocked(this);
267 DebugScopedSetImplThread
impl(this);
269 layer_tree_host_
->DeleteContentsTexturesOnImplThread(
270 layer_tree_host_impl_
->resource_provider());
271 layer_tree_host_impl_
.reset();
273 layer_tree_host_
= NULL
;
276 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw
) {
277 DCHECK(Proxy::IsImplThread());
278 UpdateBackgroundAnimateTicking();
281 void SingleThreadProxy::NotifyReadyToActivate() {
282 // Thread-only feature.
286 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
287 layer_tree_host_
->ScheduleComposite();
290 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
291 // Thread-only/Impl-side-painting-only feature.
295 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect
) {
296 // TODO(brianderson): Once we move render_widget scheduling into this class,
297 // we can treat redraw requests more efficiently than CommitAndRedraw
299 layer_tree_host_impl_
->SetViewportDamage(damage_rect
);
303 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
304 // Impl-side painting only.
308 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
309 layer_tree_host_
->ScheduleComposite();
312 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
313 scoped_ptr
<AnimationEventsVector
> events
,
314 base::Time wall_clock_time
) {
315 DCHECK(Proxy::IsImplThread());
316 DebugScopedSetMainThread
main(this);
317 layer_tree_host_
->SetAnimationEvents(events
.Pass(), wall_clock_time
);
320 bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
322 int priority_cutoff
) {
323 DCHECK(IsImplThread());
324 if (!layer_tree_host_
->contents_texture_manager())
327 return layer_tree_host_
->contents_texture_manager()->ReduceMemoryOnImplThread(
328 limit_bytes
, priority_cutoff
, layer_tree_host_impl_
->resource_provider());
331 void SingleThreadProxy::ReduceWastedContentsTextureMemoryOnImplThread() {
332 // Impl-side painting only.
336 void SingleThreadProxy::SendManagedMemoryStats() {
337 DCHECK(Proxy::IsImplThread());
338 if (!layer_tree_host_impl_
)
340 if (!layer_tree_host_
->contents_texture_manager())
343 PrioritizedResourceManager
* contents_texture_manager
=
344 layer_tree_host_
->contents_texture_manager();
345 layer_tree_host_impl_
->SendManagedMemoryStats(
346 contents_texture_manager
->MemoryVisibleBytes(),
347 contents_texture_manager
->MemoryVisibleAndNearbyBytes(),
348 contents_texture_manager
->MemoryUseBytes());
351 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_
; }
353 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
354 // Cause a commit so we can notice the lost context.
355 SetNeedsCommitOnImplThread();
358 // Called by the legacy scheduling path (e.g. where render_widget does the
360 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time
) {
361 gfx::Rect device_viewport_damage_rect
;
363 LayerTreeHostImpl::FrameData frame
;
364 if (CommitAndComposite(frame_begin_time
,
365 device_viewport_damage_rect
,
366 false, // for_readback
368 layer_tree_host_impl_
->SwapBuffers(frame
);
373 scoped_ptr
<base::Value
> SingleThreadProxy::AsValue() const {
374 scoped_ptr
<base::DictionaryValue
> state(new base::DictionaryValue());
376 // The following line casts away const modifiers because it is just
377 // setting debug state. We still want the AsValue() function and its
378 // call chain to be const throughout.
379 DebugScopedSetImplThread
impl(const_cast<SingleThreadProxy
*>(this));
381 state
->Set("layer_tree_host_impl",
382 layer_tree_host_impl_
->AsValue().release());
384 return state
.PassAs
<base::Value
>();
387 void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
389 DebugScopedSetImplThread
impl(this);
390 if (layer_tree_host_impl_
->renderer()) {
391 DCHECK(!layer_tree_host_
->output_surface_lost());
392 layer_tree_host_impl_
->renderer()->DoNoOp();
397 bool SingleThreadProxy::CommitAndComposite(
398 base::TimeTicks frame_begin_time
,
399 gfx::Rect device_viewport_damage_rect
,
401 LayerTreeHostImpl::FrameData
* frame
) {
402 DCHECK(Proxy::IsMainThread());
404 if (!layer_tree_host_
->InitializeOutputSurfaceIfNeeded())
407 layer_tree_host_
->AnimateLayers(frame_begin_time
);
409 scoped_refptr
<cc::ContextProvider
> offscreen_context_provider
;
410 if (renderer_capabilities_for_main_thread_
.using_offscreen_context3d
&&
411 layer_tree_host_
->needs_offscreen_context()) {
412 offscreen_context_provider
=
413 layer_tree_host_
->client()->OffscreenContextProviderForMainThread();
414 if (offscreen_context_provider
.get())
415 created_offscreen_context_provider_
= true;
418 if (layer_tree_host_
->contents_texture_manager()) {
419 layer_tree_host_
->contents_texture_manager()
420 ->UnlinkAndClearEvictedBackings();
423 scoped_ptr
<ResourceUpdateQueue
> queue
=
424 make_scoped_ptr(new ResourceUpdateQueue
);
425 layer_tree_host_
->UpdateLayers(
426 queue
.get(), layer_tree_host_impl_
->memory_allocation_limit_bytes());
428 layer_tree_host_
->WillCommit();
429 DoCommit(queue
.Pass());
430 bool result
= DoComposite(offscreen_context_provider
,
432 device_viewport_damage_rect
,
435 layer_tree_host_
->DidBeginFrame();
439 bool SingleThreadProxy::ShouldComposite() const {
440 DCHECK(Proxy::IsImplThread());
441 return layer_tree_host_impl_
->visible() &&
442 layer_tree_host_impl_
->CanDraw();
445 void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
446 DCHECK(Proxy::IsImplThread());
447 layer_tree_host_impl_
->UpdateBackgroundAnimateTicking(
448 !ShouldComposite() && layer_tree_host_impl_
->active_tree()->root_layer());
451 bool SingleThreadProxy::DoComposite(
452 scoped_refptr
<cc::ContextProvider
> offscreen_context_provider
,
453 base::TimeTicks frame_begin_time
,
454 gfx::Rect device_viewport_damage_rect
,
456 LayerTreeHostImpl::FrameData
* frame
) {
457 DCHECK(!layer_tree_host_
->output_surface_lost());
459 bool lost_output_surface
= false;
461 DebugScopedSetImplThread
impl(this);
462 base::AutoReset
<bool> mark_inside(&inside_draw_
, true);
464 layer_tree_host_impl_
->SetOffscreenContextProvider(
465 offscreen_context_provider
);
467 bool can_do_readback
= layer_tree_host_impl_
->renderer()->CanReadPixels();
469 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
470 // frame, so can only be used when such a frame is possible. Since
471 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
472 // CanDraw() as well.
473 if (!ShouldComposite() || (for_readback
&& !can_do_readback
)) {
474 UpdateBackgroundAnimateTicking();
478 layer_tree_host_impl_
->Animate(
479 layer_tree_host_impl_
->CurrentFrameTimeTicks(),
480 layer_tree_host_impl_
->CurrentFrameTime());
481 UpdateBackgroundAnimateTicking();
483 layer_tree_host_impl_
->PrepareToDraw(frame
, device_viewport_damage_rect
);
484 layer_tree_host_impl_
->DrawLayers(frame
, frame_begin_time
);
485 layer_tree_host_impl_
->DidDrawAllLayers(*frame
);
486 lost_output_surface
= layer_tree_host_impl_
->IsContextLost();
488 bool start_ready_animations
= true;
489 layer_tree_host_impl_
->UpdateAnimationState(start_ready_animations
);
491 layer_tree_host_impl_
->ResetCurrentFrameTimeForNextFrame();
494 if (lost_output_surface
) {
495 cc::ContextProvider
* offscreen_contexts
=
496 layer_tree_host_impl_
->offscreen_context_provider();
497 if (offscreen_contexts
)
498 offscreen_contexts
->VerifyContexts();
499 layer_tree_host_
->DidLoseOutputSurface();
506 void SingleThreadProxy::DidSwapFrame() {
507 if (next_frame_is_newly_committed_frame_
) {
508 next_frame_is_newly_committed_frame_
= false;
509 layer_tree_host_
->DidCommitAndDrawFrame();
513 bool SingleThreadProxy::CommitPendingForTesting() { return false; }