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/bind.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/trace_event/trace_event.h"
11 #include "cc/base/devtools_instrumentation.h"
12 #include "cc/benchmarks/benchmark_instrumentation.h"
13 #include "cc/input/browser_controls_offset_manager.h"
14 #include "cc/metrics/compositor_timing_history.h"
15 #include "cc/paint/paint_worklet_layer_painter.h"
16 #include "cc/resources/ui_resource_manager.h"
17 #include "cc/scheduler/commit_earlyout_reason.h"
18 #include "cc/scheduler/scheduler.h"
19 #include "cc/trees/latency_info_swap_promise.h"
20 #include "cc/trees/layer_tree_frame_sink.h"
21 #include "cc/trees/layer_tree_host.h"
22 #include "cc/trees/layer_tree_host_single_thread_client.h"
23 #include "cc/trees/layer_tree_impl.h"
24 #include "cc/trees/mutator_host.h"
25 #include "cc/trees/render_frame_metadata_observer.h"
26 #include "cc/trees/scoped_abort_remaining_swap_promises.h"
27 #include "cc/trees/scroll_and_scale_set.h"
28 #include "components/viz/common/frame_sinks/delay_based_time_source.h"
29 #include "components/viz/common/frame_timing_details.h"
30 #include "components/viz/common/gpu/context_provider.h"
31 
32 namespace cc {
33 
Create(LayerTreeHost * layer_tree_host,LayerTreeHostSingleThreadClient * client,TaskRunnerProvider * task_runner_provider)34 std::unique_ptr<Proxy> SingleThreadProxy::Create(
35     LayerTreeHost* layer_tree_host,
36     LayerTreeHostSingleThreadClient* client,
37     TaskRunnerProvider* task_runner_provider) {
38   return base::WrapUnique(
39       new SingleThreadProxy(layer_tree_host, client, task_runner_provider));
40 }
41 
SingleThreadProxy(LayerTreeHost * layer_tree_host,LayerTreeHostSingleThreadClient * client,TaskRunnerProvider * task_runner_provider)42 SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host,
43                                      LayerTreeHostSingleThreadClient* client,
44                                      TaskRunnerProvider* task_runner_provider)
45     : layer_tree_host_(layer_tree_host),
46       single_thread_client_(client),
47       task_runner_provider_(task_runner_provider),
48       next_frame_is_newly_committed_frame_(false),
49 #if DCHECK_IS_ON()
50       inside_impl_frame_(false),
51 #endif
52       inside_draw_(false),
53       defer_main_frame_update_(false),
54       defer_commits_(false),
55       animate_requested_(false),
56       commit_requested_(false),
57       inside_synchronous_composite_(false),
58       needs_impl_frame_(false),
59       layer_tree_frame_sink_creation_requested_(false),
60       layer_tree_frame_sink_lost_(true) {
61   TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
62   DCHECK(task_runner_provider_);
63   DCHECK(task_runner_provider_->IsMainThread());
64   DCHECK(layer_tree_host);
65 }
66 
Start()67 void SingleThreadProxy::Start() {
68   DebugScopedSetImplThread impl(task_runner_provider_);
69 
70   const LayerTreeSettings& settings = layer_tree_host_->GetSettings();
71   DCHECK(settings.single_thread_proxy_scheduler ||
72          !settings.enable_checker_imaging)
73       << "Checker-imaging is not supported in synchronous single threaded mode";
74   host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
75   if (settings.single_thread_proxy_scheduler && !scheduler_on_impl_thread_) {
76     SchedulerSettings scheduler_settings(settings.ToSchedulerSettings());
77     scheduler_settings.commit_to_active_tree = true;
78 
79     std::unique_ptr<CompositorTimingHistory> compositor_timing_history(
80         new CompositorTimingHistory(
81             scheduler_settings.using_synchronous_renderer_compositor,
82             CompositorTimingHistory::BROWSER_UMA,
83             layer_tree_host_->rendering_stats_instrumentation(),
84             host_impl_->compositor_frame_reporting_controller()));
85     scheduler_on_impl_thread_.reset(
86         new Scheduler(this, scheduler_settings, layer_tree_host_->GetId(),
87                       task_runner_provider_->MainThreadTaskRunner(),
88                       std::move(compositor_timing_history)));
89   }
90 }
91 
~SingleThreadProxy()92 SingleThreadProxy::~SingleThreadProxy() {
93   TRACE_EVENT0("cc", "SingleThreadProxy::~SingleThreadProxy");
94   DCHECK(task_runner_provider_->IsMainThread());
95   // Make sure Stop() got called or never Started.
96   DCHECK(!host_impl_);
97 }
98 
IsStarted() const99 bool SingleThreadProxy::IsStarted() const {
100   DCHECK(task_runner_provider_->IsMainThread());
101   return !!host_impl_;
102 }
103 
SetVisible(bool visible)104 void SingleThreadProxy::SetVisible(bool visible) {
105   TRACE_EVENT1("cc", "SingleThreadProxy::SetVisible", "visible", visible);
106   DebugScopedSetImplThread impl(task_runner_provider_);
107 
108   host_impl_->SetVisible(visible);
109 
110   if (scheduler_on_impl_thread_)
111     scheduler_on_impl_thread_->SetVisible(host_impl_->visible());
112 }
113 
RequestNewLayerTreeFrameSink()114 void SingleThreadProxy::RequestNewLayerTreeFrameSink() {
115   DCHECK(task_runner_provider_->IsMainThread());
116   layer_tree_frame_sink_creation_callback_.Cancel();
117   if (layer_tree_frame_sink_creation_requested_)
118     return;
119   layer_tree_frame_sink_creation_requested_ = true;
120   layer_tree_host_->RequestNewLayerTreeFrameSink();
121 }
122 
ReleaseLayerTreeFrameSink()123 void SingleThreadProxy::ReleaseLayerTreeFrameSink() {
124   layer_tree_frame_sink_lost_ = true;
125   frame_sink_bound_weak_factory_.InvalidateWeakPtrs();
126   if (scheduler_on_impl_thread_)
127     scheduler_on_impl_thread_->DidLoseLayerTreeFrameSink();
128   return host_impl_->ReleaseLayerTreeFrameSink();
129 }
130 
SetLayerTreeFrameSink(LayerTreeFrameSink * layer_tree_frame_sink)131 void SingleThreadProxy::SetLayerTreeFrameSink(
132     LayerTreeFrameSink* layer_tree_frame_sink) {
133   DCHECK(task_runner_provider_->IsMainThread());
134   DCHECK(layer_tree_frame_sink_creation_requested_);
135 
136   bool success;
137   {
138     DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
139     DebugScopedSetImplThread impl(task_runner_provider_);
140     success = host_impl_->InitializeFrameSink(layer_tree_frame_sink);
141   }
142 
143   if (success) {
144     frame_sink_bound_weak_ptr_ = frame_sink_bound_weak_factory_.GetWeakPtr();
145     layer_tree_host_->DidInitializeLayerTreeFrameSink();
146     if (scheduler_on_impl_thread_)
147       scheduler_on_impl_thread_->DidCreateAndInitializeLayerTreeFrameSink();
148     else if (!inside_synchronous_composite_)
149       SetNeedsCommit();
150     layer_tree_frame_sink_creation_requested_ = false;
151     layer_tree_frame_sink_lost_ = false;
152   } else {
153     // DidFailToInitializeLayerTreeFrameSink is treated as a
154     // RequestNewLayerTreeFrameSink, and so
155     // layer_tree_frame_sink_creation_requested remains true.
156     layer_tree_host_->DidFailToInitializeLayerTreeFrameSink();
157   }
158 }
159 
SetNeedsAnimate()160 void SingleThreadProxy::SetNeedsAnimate() {
161   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
162   DCHECK(task_runner_provider_->IsMainThread());
163   if (animate_requested_)
164     return;
165   animate_requested_ = true;
166   DebugScopedSetImplThread impl(task_runner_provider_);
167   if (scheduler_on_impl_thread_)
168     scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
169 }
170 
SetNeedsUpdateLayers()171 void SingleThreadProxy::SetNeedsUpdateLayers() {
172   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
173   DCHECK(task_runner_provider_->IsMainThread());
174   SetNeedsCommit();
175 }
176 
DoCommit(const viz::BeginFrameArgs & commit_args)177 void SingleThreadProxy::DoCommit(const viz::BeginFrameArgs& commit_args) {
178   TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
179   DCHECK(task_runner_provider_->IsMainThread());
180 
181   layer_tree_host_->WillCommit();
182   devtools_instrumentation::ScopedCommitTrace commit_task(
183       layer_tree_host_->GetId());
184 
185   // Commit immediately.
186   {
187     DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
188     DebugScopedSetImplThread impl(task_runner_provider_);
189 
190     host_impl_->ReadyToCommit(commit_args);
191     host_impl_->BeginCommit();
192 
193     if (host_impl_->EvictedUIResourcesExist())
194       layer_tree_host_->GetUIResourceManager()->RecreateUIResources();
195 
196     layer_tree_host_->FinishCommitOnImplThread(host_impl_.get());
197 
198     if (scheduler_on_impl_thread_) {
199       scheduler_on_impl_thread_->DidCommit();
200     }
201 
202     IssueImageDecodeFinishedCallbacks();
203     host_impl_->CommitComplete();
204 
205     // Commit goes directly to the active tree, but we need to synchronously
206     // "activate" the tree still during commit to satisfy any potential
207     // SetNextCommitWaitsForActivation calls.  Unfortunately, the tree
208     // might not be ready to draw, so DidActivateSyncTree must set
209     // the flag to force the tree to not draw until textures are ready.
210     NotifyReadyToActivate();
211   }
212 }
213 
IssueImageDecodeFinishedCallbacks()214 void SingleThreadProxy::IssueImageDecodeFinishedCallbacks() {
215   DCHECK(task_runner_provider_->IsImplThread());
216 
217   layer_tree_host_->ImageDecodesFinished(
218       host_impl_->TakeCompletedImageDecodeRequests());
219 }
220 
CommitComplete()221 void SingleThreadProxy::CommitComplete() {
222   // Commit complete happens on the main side after activate to satisfy any
223   // SetNextCommitWaitsForActivation calls.
224   DCHECK(!host_impl_->pending_tree())
225       << "Activation is expected to have synchronously occurred by now.";
226 
227   DebugScopedSetMainThread main(task_runner_provider_);
228   layer_tree_host_->CommitComplete();
229   layer_tree_host_->DidBeginMainFrame();
230 
231   next_frame_is_newly_committed_frame_ = true;
232 }
233 
SetNeedsCommit()234 void SingleThreadProxy::SetNeedsCommit() {
235   DCHECK(task_runner_provider_->IsMainThread());
236   single_thread_client_->RequestScheduleComposite();
237   if (commit_requested_)
238     return;
239   commit_requested_ = true;
240   DebugScopedSetImplThread impl(task_runner_provider_);
241   if (scheduler_on_impl_thread_)
242     scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
243 }
244 
SetNeedsRedraw(const gfx::Rect & damage_rect)245 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
246   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
247   DCHECK(task_runner_provider_->IsMainThread());
248   DebugScopedSetImplThread impl(task_runner_provider_);
249   host_impl_->SetViewportDamage(damage_rect);
250   SetNeedsRedrawOnImplThread();
251 }
252 
SetNextCommitWaitsForActivation()253 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
254   // Activation always forced in commit, so nothing to do.
255   DCHECK(task_runner_provider_->IsMainThread());
256 }
257 
RequestedAnimatePending()258 bool SingleThreadProxy::RequestedAnimatePending() {
259   return animate_requested_ || commit_requested_ || needs_impl_frame_;
260 }
261 
SetDeferMainFrameUpdate(bool defer_main_frame_update)262 void SingleThreadProxy::SetDeferMainFrameUpdate(bool defer_main_frame_update) {
263   DCHECK(task_runner_provider_->IsMainThread());
264   // Deferring main frame updates only makes sense if there's a scheduler.
265   if (!scheduler_on_impl_thread_)
266     return;
267   if (defer_main_frame_update_ == defer_main_frame_update)
268     return;
269 
270   if (defer_main_frame_update) {
271     TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
272         "cc", "SingleThreadProxy::SetDeferMainFrameUpdate",
273         TRACE_ID_LOCAL(this));
274   } else {
275     TRACE_EVENT_NESTABLE_ASYNC_END0(
276         "cc", "SingleThreadProxy::SetDeferMainFrameUpdate",
277         TRACE_ID_LOCAL(this));
278   }
279 
280   defer_main_frame_update_ = defer_main_frame_update;
281 
282   // Notify dependent systems that the deferral status has changed.
283   layer_tree_host_->OnDeferMainFrameUpdatesChanged(defer_main_frame_update_);
284 
285   // The scheduler needs to know that it should not issue BeginMainFrame.
286   scheduler_on_impl_thread_->SetDeferBeginMainFrame(defer_main_frame_update_);
287 }
288 
StartDeferringCommits(base::TimeDelta timeout)289 void SingleThreadProxy::StartDeferringCommits(base::TimeDelta timeout) {
290   DCHECK(task_runner_provider_->IsMainThread());
291 
292   // Do nothing if already deferring. The timeout remains as it was from when
293   // we most recently began deferring.
294   if (defer_commits_)
295     return;
296 
297   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits",
298                                     TRACE_ID_LOCAL(this));
299 
300   defer_commits_ = true;
301   commits_restart_time_ = base::TimeTicks::Now() + timeout;
302 
303   // Notify dependent systems that the deferral status has changed.
304   layer_tree_host_->OnDeferCommitsChanged(defer_commits_);
305 }
306 
StopDeferringCommits(PaintHoldingCommitTrigger trigger)307 void SingleThreadProxy::StopDeferringCommits(
308     PaintHoldingCommitTrigger trigger) {
309   if (!defer_commits_)
310     return;
311   defer_commits_ = false;
312   commits_restart_time_ = base::TimeTicks();
313   UMA_HISTOGRAM_ENUMERATION("PaintHolding.CommitTrigger2", trigger);
314   TRACE_EVENT_NESTABLE_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits",
315                                   TRACE_ID_LOCAL(this));
316 
317   // Notify dependent systems that the deferral status has changed.
318   layer_tree_host_->OnDeferCommitsChanged(defer_commits_);
319 }
320 
CommitRequested() const321 bool SingleThreadProxy::CommitRequested() const {
322   DCHECK(task_runner_provider_->IsMainThread());
323   return commit_requested_;
324 }
325 
Stop()326 void SingleThreadProxy::Stop() {
327   TRACE_EVENT0("cc", "SingleThreadProxy::stop");
328   DCHECK(task_runner_provider_->IsMainThread());
329   {
330     DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
331     DebugScopedSetImplThread impl(task_runner_provider_);
332 
333     // Prevent the scheduler from performing actions while we're in an
334     // inconsistent state.
335     if (scheduler_on_impl_thread_)
336       scheduler_on_impl_thread_->Stop();
337     // Take away the LayerTreeFrameSink before destroying things so it doesn't
338     // try to call into its client mid-shutdown.
339     host_impl_->ReleaseLayerTreeFrameSink();
340 
341     // It is important to destroy LTHI before the Scheduler since it can make
342     // callbacks that access it during destruction cleanup.
343     host_impl_ = nullptr;
344     scheduler_on_impl_thread_ = nullptr;
345   }
346   layer_tree_host_ = nullptr;
347 }
348 
SetMutator(std::unique_ptr<LayerTreeMutator> mutator)349 void SingleThreadProxy::SetMutator(std::unique_ptr<LayerTreeMutator> mutator) {
350   DCHECK(task_runner_provider_->IsMainThread());
351   DebugScopedSetImplThread impl(task_runner_provider_);
352   host_impl_->SetLayerTreeMutator(std::move(mutator));
353 }
354 
SetPaintWorkletLayerPainter(std::unique_ptr<PaintWorkletLayerPainter> painter)355 void SingleThreadProxy::SetPaintWorkletLayerPainter(
356     std::unique_ptr<PaintWorkletLayerPainter> painter) {
357   NOTREACHED();
358 }
359 
OnCanDrawStateChanged(bool can_draw)360 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
361   TRACE_EVENT1("cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw",
362                can_draw);
363   DCHECK(task_runner_provider_->IsImplThread());
364   if (scheduler_on_impl_thread_)
365     scheduler_on_impl_thread_->SetCanDraw(can_draw);
366 }
367 
NotifyReadyToActivate()368 void SingleThreadProxy::NotifyReadyToActivate() {
369   TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToActivate");
370   DebugScopedSetImplThread impl(task_runner_provider_);
371   if (scheduler_on_impl_thread_)
372     scheduler_on_impl_thread_->NotifyReadyToActivate();
373 }
374 
NotifyReadyToDraw()375 void SingleThreadProxy::NotifyReadyToDraw() {
376   TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToDraw");
377   DebugScopedSetImplThread impl(task_runner_provider_);
378   if (scheduler_on_impl_thread_)
379     scheduler_on_impl_thread_->NotifyReadyToDraw();
380 }
381 
SetNeedsRedrawOnImplThread()382 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
383   single_thread_client_->RequestScheduleComposite();
384   if (scheduler_on_impl_thread_)
385     scheduler_on_impl_thread_->SetNeedsRedraw();
386 }
387 
SetNeedsOneBeginImplFrameOnImplThread()388 void SingleThreadProxy::SetNeedsOneBeginImplFrameOnImplThread() {
389   TRACE_EVENT0("cc",
390                "SingleThreadProxy::SetNeedsOneBeginImplFrameOnImplThread");
391   single_thread_client_->RequestScheduleComposite();
392   if (scheduler_on_impl_thread_)
393     scheduler_on_impl_thread_->SetNeedsOneBeginImplFrame();
394   needs_impl_frame_ = true;
395 }
396 
SetNeedsPrepareTilesOnImplThread()397 void SingleThreadProxy::SetNeedsPrepareTilesOnImplThread() {
398   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsPrepareTilesOnImplThread");
399   if (scheduler_on_impl_thread_)
400     scheduler_on_impl_thread_->SetNeedsPrepareTiles();
401 }
402 
SetNeedsCommitOnImplThread()403 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
404   single_thread_client_->RequestScheduleComposite();
405   if (scheduler_on_impl_thread_)
406     scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
407   commit_requested_ = true;
408 }
409 
SetVideoNeedsBeginFrames(bool needs_begin_frames)410 void SingleThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) {
411   TRACE_EVENT1("cc", "SingleThreadProxy::SetVideoNeedsBeginFrames",
412                "needs_begin_frames", needs_begin_frames);
413   // In tests the layer tree is destroyed after the scheduler is.
414   if (scheduler_on_impl_thread_)
415     scheduler_on_impl_thread_->SetVideoNeedsBeginFrames(needs_begin_frames);
416 }
417 
CompositedAnimationsCount() const418 size_t SingleThreadProxy::CompositedAnimationsCount() const {
419   return 0;
420 }
421 
MainThreadAnimationsCount() const422 size_t SingleThreadProxy::MainThreadAnimationsCount() const {
423   return 0;
424 }
425 
HasCustomPropertyAnimations() const426 bool SingleThreadProxy::HasCustomPropertyAnimations() const {
427   return false;
428 }
429 
CurrentFrameHadRAF() const430 bool SingleThreadProxy::CurrentFrameHadRAF() const {
431   return false;
432 }
433 
NextFrameHasPendingRAF() const434 bool SingleThreadProxy::NextFrameHasPendingRAF() const {
435   return false;
436 }
437 
IsInsideDraw()438 bool SingleThreadProxy::IsInsideDraw() {
439   return inside_draw_;
440 }
441 
IsBeginMainFrameExpected()442 bool SingleThreadProxy::IsBeginMainFrameExpected() {
443   return true;
444 }
445 
DidActivateSyncTree()446 void SingleThreadProxy::DidActivateSyncTree() {
447   CommitComplete();
448 }
449 
WillPrepareTiles()450 void SingleThreadProxy::WillPrepareTiles() {
451   DCHECK(task_runner_provider_->IsImplThread());
452   if (scheduler_on_impl_thread_)
453     scheduler_on_impl_thread_->WillPrepareTiles();
454 }
455 
DidPrepareTiles()456 void SingleThreadProxy::DidPrepareTiles() {
457   DCHECK(task_runner_provider_->IsImplThread());
458   if (scheduler_on_impl_thread_)
459     scheduler_on_impl_thread_->DidPrepareTiles();
460 }
461 
DidCompletePageScaleAnimationOnImplThread()462 void SingleThreadProxy::DidCompletePageScaleAnimationOnImplThread() {
463   layer_tree_host_->DidCompletePageScaleAnimation();
464 }
465 
DidLoseLayerTreeFrameSinkOnImplThread()466 void SingleThreadProxy::DidLoseLayerTreeFrameSinkOnImplThread() {
467   TRACE_EVENT0("cc",
468                "SingleThreadProxy::DidLoseLayerTreeFrameSinkOnImplThread");
469   {
470     DebugScopedSetMainThread main(task_runner_provider_);
471     // This must happen before we notify the scheduler as it may try to recreate
472     // the output surface if already in BEGIN_IMPL_FRAME_STATE_IDLE.
473     layer_tree_host_->DidLoseLayerTreeFrameSink();
474   }
475   single_thread_client_->DidLoseLayerTreeFrameSink();
476   if (scheduler_on_impl_thread_)
477     scheduler_on_impl_thread_->DidLoseLayerTreeFrameSink();
478   layer_tree_frame_sink_lost_ = true;
479 }
480 
SetBeginFrameSource(viz::BeginFrameSource * source)481 void SingleThreadProxy::SetBeginFrameSource(viz::BeginFrameSource* source) {
482   if (scheduler_on_impl_thread_)
483     scheduler_on_impl_thread_->SetBeginFrameSource(source);
484 }
485 
DidReceiveCompositorFrameAckOnImplThread()486 void SingleThreadProxy::DidReceiveCompositorFrameAckOnImplThread() {
487   TRACE_EVENT0("cc,benchmark",
488                "SingleThreadProxy::DidReceiveCompositorFrameAckOnImplThread");
489   if (scheduler_on_impl_thread_)
490     scheduler_on_impl_thread_->DidReceiveCompositorFrameAck();
491   if (layer_tree_host_->GetSettings().send_compositor_frame_ack) {
492     // We do a PostTask here because freeing resources in some cases (such as in
493     // TextureLayer) is PostTasked and we want to make sure ack is received
494     // after resources are returned.
495     task_runner_provider_->MainThreadTaskRunner()->PostTask(
496         FROM_HERE,
497         base::BindOnce(&SingleThreadProxy::DidReceiveCompositorFrameAck,
498                        frame_sink_bound_weak_ptr_));
499   }
500 }
501 
OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,bool skip_draw)502 void SingleThreadProxy::OnDrawForLayerTreeFrameSink(
503     bool resourceless_software_draw,
504     bool skip_draw) {
505   NOTREACHED() << "Implemented by ThreadProxy for synchronous compositor.";
506 }
507 
NeedsImplSideInvalidation(bool needs_first_draw_on_activation)508 void SingleThreadProxy::NeedsImplSideInvalidation(
509     bool needs_first_draw_on_activation) {
510   if (scheduler_on_impl_thread_) {
511     scheduler_on_impl_thread_->SetNeedsImplSideInvalidation(
512         needs_first_draw_on_activation);
513   }
514 }
515 
NotifyImageDecodeRequestFinished()516 void SingleThreadProxy::NotifyImageDecodeRequestFinished() {
517   // If we don't have a scheduler, then just issue the callbacks here.
518   // Otherwise, schedule a commit.
519   if (!scheduler_on_impl_thread_) {
520     DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
521     DebugScopedSetImplThread impl(task_runner_provider_);
522 
523     IssueImageDecodeFinishedCallbacks();
524     return;
525   }
526   SetNeedsCommitOnImplThread();
527 }
528 
DidPresentCompositorFrameOnImplThread(uint32_t frame_token,std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,const viz::FrameTimingDetails & details)529 void SingleThreadProxy::DidPresentCompositorFrameOnImplThread(
530     uint32_t frame_token,
531     std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
532     const viz::FrameTimingDetails& details) {
533   layer_tree_host_->DidPresentCompositorFrame(frame_token, std::move(callbacks),
534                                               details.presentation_feedback);
535 
536   if (scheduler_on_impl_thread_) {
537     scheduler_on_impl_thread_->DidPresentCompositorFrame(frame_token, details);
538   }
539 }
540 
NotifyAnimationWorkletStateChange(AnimationWorkletMutationState state,ElementListType element_list_type)541 void SingleThreadProxy::NotifyAnimationWorkletStateChange(
542     AnimationWorkletMutationState state,
543     ElementListType element_list_type) {
544   layer_tree_host_->NotifyAnimationWorkletStateChange(state, element_list_type);
545 }
546 
NotifyPaintWorkletStateChange(Scheduler::PaintWorkletState state)547 void SingleThreadProxy::NotifyPaintWorkletStateChange(
548     Scheduler::PaintWorkletState state) {
549   // Off-Thread PaintWorklet is only supported on the threaded compositor.
550   NOTREACHED();
551 }
552 
RequestBeginMainFrameNotExpected(bool new_state)553 void SingleThreadProxy::RequestBeginMainFrameNotExpected(bool new_state) {
554   if (scheduler_on_impl_thread_) {
555     scheduler_on_impl_thread_->SetMainThreadWantsBeginMainFrameNotExpected(
556         new_state);
557   }
558 }
559 
CompositeImmediately(base::TimeTicks frame_begin_time,bool raster)560 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time,
561                                              bool raster) {
562   TRACE_EVENT0("cc,benchmark", "SingleThreadProxy::CompositeImmediately");
563   DCHECK(task_runner_provider_->IsMainThread());
564 #if DCHECK_IS_ON()
565   DCHECK(!inside_impl_frame_);
566 #endif
567   base::AutoReset<bool> inside_composite(&inside_synchronous_composite_, true);
568 
569   if (layer_tree_frame_sink_lost_) {
570     RequestNewLayerTreeFrameSink();
571     // RequestNewLayerTreeFrameSink could have synchronously created an output
572     // surface, so check again before returning.
573     if (layer_tree_frame_sink_lost_)
574       return;
575   }
576 
577   viz::BeginFrameArgs begin_frame_args(viz::BeginFrameArgs::Create(
578       BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId,
579       begin_frame_sequence_number_++, frame_begin_time, base::TimeTicks(),
580       viz::BeginFrameArgs::DefaultInterval(), viz::BeginFrameArgs::NORMAL));
581 
582   // Start the impl frame.
583   {
584     DebugScopedSetImplThread impl(task_runner_provider_);
585     WillBeginImplFrame(begin_frame_args);
586   }
587 
588   // Run the "main thread" and get it to commit.
589   {
590 #if DCHECK_IS_ON()
591     DCHECK(inside_impl_frame_);
592 #endif
593     animate_requested_ = false;
594     needs_impl_frame_ = false;
595     // Prevent new commits from being requested inside DoBeginMainFrame.
596     // Note: We do not want to prevent SetNeedsAnimate from requesting
597     // a commit here.
598     commit_requested_ = true;
599     DoBeginMainFrame(begin_frame_args);
600     commit_requested_ = false;
601     DoPainting();
602     DoCommit(begin_frame_args);
603 
604     DCHECK_EQ(
605         0u,
606         layer_tree_host_->GetSwapPromiseManager()->num_queued_swap_promises())
607         << "Commit should always succeed and transfer promises.";
608   }
609 
610   // Finish the impl frame.
611   {
612     DebugScopedSetImplThread impl(task_runner_provider_);
613     host_impl_->ActivateSyncTree();
614     if (raster) {
615       host_impl_->PrepareTiles();
616       host_impl_->SynchronouslyInitializeAllTiles();
617     }
618 
619     // TODO(danakj): Don't do this last... we prepared the wrong things. D:
620     host_impl_->Animate();
621 
622     if (raster) {
623       LayerTreeHostImpl::FrameData frame;
624       frame.begin_frame_ack = viz::BeginFrameAck(begin_frame_args, true);
625       frame.origin_begin_main_frame_args = begin_frame_args;
626       DoComposite(&frame);
627     }
628 
629     // DoComposite could abort, but because this is a synchronous composite
630     // another draw will never be scheduled, so break remaining promises.
631     host_impl_->active_tree()->BreakSwapPromises(SwapPromise::SWAP_FAILS);
632 
633     DidFinishImplFrame();
634   }
635 }
636 
SupportsImplScrolling() const637 bool SingleThreadProxy::SupportsImplScrolling() const {
638   return false;
639 }
640 
ShouldComposite() const641 bool SingleThreadProxy::ShouldComposite() const {
642   DCHECK(task_runner_provider_->IsImplThread());
643   return host_impl_->visible() && host_impl_->CanDraw();
644 }
645 
ScheduleRequestNewLayerTreeFrameSink()646 void SingleThreadProxy::ScheduleRequestNewLayerTreeFrameSink() {
647   if (layer_tree_frame_sink_creation_callback_.IsCancelled() &&
648       !layer_tree_frame_sink_creation_requested_) {
649     layer_tree_frame_sink_creation_callback_.Reset(
650         base::BindOnce(&SingleThreadProxy::RequestNewLayerTreeFrameSink,
651                        weak_factory_.GetWeakPtr()));
652     task_runner_provider_->MainThreadTaskRunner()->PostTask(
653         FROM_HERE, layer_tree_frame_sink_creation_callback_.callback());
654   }
655 }
656 
DoComposite(LayerTreeHostImpl::FrameData * frame)657 DrawResult SingleThreadProxy::DoComposite(LayerTreeHostImpl::FrameData* frame) {
658   TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
659 
660   DrawResult draw_result;
661   bool draw_frame;
662   {
663     DebugScopedSetImplThread impl(task_runner_provider_);
664     base::AutoReset<bool> mark_inside(&inside_draw_, true);
665 
666     // We guard PrepareToDraw() with CanDraw() because it always returns a valid
667     // frame, so can only be used when such a frame is possible. Since
668     // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
669     // CanDraw() as well.
670     if (!ShouldComposite()) {
671       return DRAW_ABORTED_CANT_DRAW;
672     }
673 
674     // This CapturePostTasks should be destroyed before
675     // DidCommitAndDrawFrame() is called since that goes out to the
676     // embedder, and we want the embedder to receive its callbacks before that.
677     // NOTE: This maintains consistent ordering with the ThreadProxy since
678     // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
679     // there as the main thread is not blocked, so any posted tasks inside
680     // the swap buffers will execute first.
681     DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
682 
683     draw_result = host_impl_->PrepareToDraw(frame);
684     draw_frame = draw_result == DRAW_SUCCESS;
685     if (draw_frame) {
686       if (host_impl_->DrawLayers(frame)) {
687         if (scheduler_on_impl_thread_) {
688           // Drawing implies we submitted a frame to the LayerTreeFrameSink.
689           scheduler_on_impl_thread_->DidSubmitCompositorFrame(
690               frame->frame_token, host_impl_->TakeEventsMetrics());
691         }
692         single_thread_client_->DidSubmitCompositorFrame();
693       }
694     }
695     host_impl_->DidDrawAllLayers(*frame);
696 
697     bool start_ready_animations = draw_frame;
698     host_impl_->UpdateAnimationState(start_ready_animations);
699   }
700   DidCommitAndDrawFrame();
701 
702   return draw_result;
703 }
704 
DidCommitAndDrawFrame()705 void SingleThreadProxy::DidCommitAndDrawFrame() {
706   if (next_frame_is_newly_committed_frame_) {
707     DebugScopedSetMainThread main(task_runner_provider_);
708     next_frame_is_newly_committed_frame_ = false;
709     layer_tree_host_->DidCommitAndDrawFrame();
710   }
711 }
712 
MainFrameWillHappenForTesting()713 bool SingleThreadProxy::MainFrameWillHappenForTesting() {
714   if (!scheduler_on_impl_thread_)
715     return false;
716   return scheduler_on_impl_thread_->MainFrameForTestingWillHappen();
717 }
718 
ClearHistory()719 void SingleThreadProxy::ClearHistory() {
720   DCHECK(task_runner_provider_->IsImplThread());
721   if (scheduler_on_impl_thread_)
722     scheduler_on_impl_thread_->ClearHistory();
723 }
724 
SetRenderFrameObserver(std::unique_ptr<RenderFrameMetadataObserver> observer)725 void SingleThreadProxy::SetRenderFrameObserver(
726     std::unique_ptr<RenderFrameMetadataObserver> observer) {
727   host_impl_->SetRenderFrameObserver(std::move(observer));
728 }
729 
UpdateBrowserControlsState(BrowserControlsState constraints,BrowserControlsState current,bool animate)730 void SingleThreadProxy::UpdateBrowserControlsState(
731     BrowserControlsState constraints,
732     BrowserControlsState current,
733     bool animate) {
734   host_impl_->browser_controls_manager()->UpdateBrowserControlsState(
735       constraints, current, animate);
736 }
737 
WillBeginImplFrame(const viz::BeginFrameArgs & args)738 bool SingleThreadProxy::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
739   DebugScopedSetImplThread impl(task_runner_provider_);
740 #if DCHECK_IS_ON()
741   DCHECK(!inside_impl_frame_)
742       << "WillBeginImplFrame called while already inside an impl frame!";
743   inside_impl_frame_ = true;
744 #endif
745   return host_impl_->WillBeginImplFrame(args);
746 }
747 
ScheduledActionSendBeginMainFrame(const viz::BeginFrameArgs & begin_frame_args)748 void SingleThreadProxy::ScheduledActionSendBeginMainFrame(
749     const viz::BeginFrameArgs& begin_frame_args) {
750   TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionSendBeginMainFrame");
751 #if DCHECK_IS_ON()
752   // Although this proxy is single-threaded, it's problematic to synchronously
753   // have BeginMainFrame happen after ScheduledActionSendBeginMainFrame.  This
754   // could cause a commit to occur in between a series of SetNeedsCommit calls
755   // (i.e. property modifications) causing some to fall on one frame and some to
756   // fall on the next.  Doing it asynchronously instead matches the semantics of
757   // ThreadProxy::SetNeedsCommit where SetNeedsCommit will not cause a
758   // synchronous commit.
759   DCHECK(inside_impl_frame_)
760       << "BeginMainFrame should only be sent inside a BeginImplFrame";
761 #endif
762 
763   host_impl_->WillSendBeginMainFrame();
764   task_runner_provider_->MainThreadTaskRunner()->PostTask(
765       FROM_HERE, base::BindOnce(&SingleThreadProxy::BeginMainFrame,
766                                 weak_factory_.GetWeakPtr(), begin_frame_args));
767   host_impl_->DidSendBeginMainFrame(begin_frame_args);
768 }
769 
FrameIntervalUpdated(base::TimeDelta interval)770 void SingleThreadProxy::FrameIntervalUpdated(base::TimeDelta interval) {
771   DebugScopedSetMainThread main(task_runner_provider_);
772   single_thread_client_->FrameIntervalUpdated(interval);
773 }
774 
SendBeginMainFrameNotExpectedSoon()775 void SingleThreadProxy::SendBeginMainFrameNotExpectedSoon() {
776   layer_tree_host_->BeginMainFrameNotExpectedSoon();
777 }
778 
ScheduledActionBeginMainFrameNotExpectedUntil(base::TimeTicks time)779 void SingleThreadProxy::ScheduledActionBeginMainFrameNotExpectedUntil(
780     base::TimeTicks time) {
781   layer_tree_host_->BeginMainFrameNotExpectedUntil(time);
782 }
783 
BeginMainFrame(const viz::BeginFrameArgs & begin_frame_args)784 void SingleThreadProxy::BeginMainFrame(
785     const viz::BeginFrameArgs& begin_frame_args) {
786   // This checker assumes NotifyReadyToCommit in this stack causes a synchronous
787   // commit.
788   ScopedAbortRemainingSwapPromises swap_promise_checker(
789       layer_tree_host_->GetSwapPromiseManager());
790 
791   if (scheduler_on_impl_thread_) {
792     scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(
793         base::TimeTicks::Now());
794   }
795 
796   commit_requested_ = false;
797   needs_impl_frame_ = false;
798   animate_requested_ = false;
799 
800   if (defer_main_frame_update_) {
801     TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferBeginMainFrame",
802                          TRACE_EVENT_SCOPE_THREAD);
803     BeginMainFrameAbortedOnImplThread(
804         CommitEarlyOutReason::ABORTED_DEFERRED_MAIN_FRAME_UPDATE);
805     return;
806   }
807 
808   if (!layer_tree_host_->IsVisible()) {
809     TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
810     BeginMainFrameAbortedOnImplThread(
811         CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
812     return;
813   }
814 
815   // Prevent new commits from being requested inside DoBeginMainFrame.
816   // Note: We do not want to prevent SetNeedsAnimate from requesting
817   // a commit here.
818   commit_requested_ = true;
819 
820   // Check now if we should stop deferring commits. Do this before
821   // DoBeginMainFrame because the latter updates scroll offsets, which
822   // we should avoid if deferring commits.
823   if (defer_commits_ && base::TimeTicks::Now() > commits_restart_time_)
824     StopDeferringCommits(PaintHoldingCommitTrigger::kTimeout);
825 
826   DoBeginMainFrame(begin_frame_args);
827 
828   // New commits requested inside UpdateLayers should be respected.
829   commit_requested_ = false;
830 
831   // At this point the main frame may have deferred commits to avoid committing
832   // right now.
833   if (defer_main_frame_update_ || defer_commits_ ||
834       begin_frame_args.animate_only) {
835     TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit_InsideBeginMainFrame",
836                          TRACE_EVENT_SCOPE_THREAD);
837     BeginMainFrameAbortedOnImplThread(
838         CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT);
839     layer_tree_host_->DidBeginMainFrame();
840     return;
841   }
842 
843   DoPainting();
844 }
845 
DoBeginMainFrame(const viz::BeginFrameArgs & begin_frame_args)846 void SingleThreadProxy::DoBeginMainFrame(
847     const viz::BeginFrameArgs& begin_frame_args) {
848   // Only update scroll deltas if we are going to commit the frame, otherwise
849   // scroll offsets get confused.
850   if (!defer_commits_) {
851     // The impl-side scroll deltas may be manipulated directly via the
852     // InputHandler on the UI thread and the scale deltas may change when they
853     // are clamped on the impl thread.
854     std::unique_ptr<ScrollAndScaleSet> scroll_info =
855         host_impl_->ProcessScrollDeltas();
856     layer_tree_host_->ApplyScrollAndScale(scroll_info.get());
857   }
858   layer_tree_host_->ApplyMutatorEvents(host_impl_->TakeMutatorEvents());
859   layer_tree_host_->WillBeginMainFrame();
860   layer_tree_host_->BeginMainFrame(begin_frame_args);
861   layer_tree_host_->AnimateLayers(begin_frame_args.frame_time);
862   layer_tree_host_->RequestMainFrameUpdate(false /* record_cc_metrics */);
863 }
864 
DoPainting()865 void SingleThreadProxy::DoPainting() {
866   layer_tree_host_->UpdateLayers();
867 
868   // TODO(enne): SingleThreadProxy does not support cancelling commits yet,
869   // search for CommitEarlyOutReason::FINISHED_NO_UPDATES inside
870   // thread_proxy.cc
871   if (scheduler_on_impl_thread_) {
872     scheduler_on_impl_thread_->NotifyReadyToCommit(
873         layer_tree_host_->begin_main_frame_metrics());
874   }
875 }
876 
BeginMainFrameAbortedOnImplThread(CommitEarlyOutReason reason)877 void SingleThreadProxy::BeginMainFrameAbortedOnImplThread(
878     CommitEarlyOutReason reason) {
879   DebugScopedSetImplThread impl(task_runner_provider_);
880   DCHECK(scheduler_on_impl_thread_->CommitPending());
881   DCHECK(!host_impl_->pending_tree());
882 
883   std::vector<std::unique_ptr<SwapPromise>> empty_swap_promises;
884   host_impl_->BeginMainFrameAborted(
885       reason, std::move(empty_swap_promises),
886       scheduler_on_impl_thread_->last_dispatched_begin_main_frame_args());
887   scheduler_on_impl_thread_->BeginMainFrameAborted(reason);
888 }
889 
ScheduledActionDrawIfPossible()890 DrawResult SingleThreadProxy::ScheduledActionDrawIfPossible() {
891   DebugScopedSetImplThread impl(task_runner_provider_);
892   LayerTreeHostImpl::FrameData frame;
893   frame.begin_frame_ack =
894       scheduler_on_impl_thread_->CurrentBeginFrameAckForActiveTree();
895   frame.origin_begin_main_frame_args =
896       scheduler_on_impl_thread_->last_activate_origin_frame_args();
897   return DoComposite(&frame);
898 }
899 
ScheduledActionDrawForced()900 DrawResult SingleThreadProxy::ScheduledActionDrawForced() {
901   NOTREACHED();
902   return INVALID_RESULT;
903 }
904 
ScheduledActionCommit()905 void SingleThreadProxy::ScheduledActionCommit() {
906   DebugScopedSetMainThread main(task_runner_provider_);
907   DoCommit(scheduler_on_impl_thread_->last_dispatched_begin_main_frame_args());
908 }
909 
ScheduledActionActivateSyncTree()910 void SingleThreadProxy::ScheduledActionActivateSyncTree() {
911   DebugScopedSetImplThread impl(task_runner_provider_);
912   host_impl_->ActivateSyncTree();
913 }
914 
ScheduledActionBeginLayerTreeFrameSinkCreation()915 void SingleThreadProxy::ScheduledActionBeginLayerTreeFrameSinkCreation() {
916   DebugScopedSetMainThread main(task_runner_provider_);
917   DCHECK(scheduler_on_impl_thread_);
918   // If possible, create the output surface in a post task.  Synchronously
919   // creating the output surface makes tests more awkward since this differs
920   // from the ThreadProxy behavior.  However, sometimes there is no
921   // task runner.
922   if (task_runner_provider_->MainThreadTaskRunner()) {
923     ScheduleRequestNewLayerTreeFrameSink();
924   } else {
925     RequestNewLayerTreeFrameSink();
926   }
927 }
928 
ScheduledActionPrepareTiles()929 void SingleThreadProxy::ScheduledActionPrepareTiles() {
930   TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionPrepareTiles");
931   DebugScopedSetImplThread impl(task_runner_provider_);
932   host_impl_->PrepareTiles();
933 }
934 
ScheduledActionInvalidateLayerTreeFrameSink(bool needs_redraw)935 void SingleThreadProxy::ScheduledActionInvalidateLayerTreeFrameSink(
936     bool needs_redraw) {
937   // This is an Android WebView codepath, which only uses multi-thread
938   // compositor. So this should not occur in single-thread mode.
939   NOTREACHED() << "Android Webview use-case, so multi-thread only";
940 }
941 
ScheduledActionPerformImplSideInvalidation()942 void SingleThreadProxy::ScheduledActionPerformImplSideInvalidation() {
943   DCHECK(scheduler_on_impl_thread_);
944 
945   DebugScopedSetImplThread impl(task_runner_provider_);
946   host_impl_->InvalidateContentOnImplSide();
947 
948   // Invalidations go directly to the active tree, so we synchronously call
949   // NotifyReadyToActivate to update the scheduler and LTHI state correctly.
950   // Since in single-threaded mode the scheduler will wait for a ready to draw
951   // signal from LTHI, the draw will remain blocked till the invalidated tiles
952   // are ready.
953   NotifyReadyToActivate();
954 }
955 
DidFinishImplFrame()956 void SingleThreadProxy::DidFinishImplFrame() {
957   host_impl_->DidFinishImplFrame(
958       scheduler_on_impl_thread_->last_activate_origin_frame_args());
959 #if DCHECK_IS_ON()
960   DCHECK(inside_impl_frame_)
961       << "DidFinishImplFrame called while not inside an impl frame!";
962   inside_impl_frame_ = false;
963 #endif
964 }
965 
DidNotProduceFrame(const viz::BeginFrameAck & ack,FrameSkippedReason reason)966 void SingleThreadProxy::DidNotProduceFrame(const viz::BeginFrameAck& ack,
967                                            FrameSkippedReason reason) {
968   DebugScopedSetImplThread impl(task_runner_provider_);
969   host_impl_->DidNotProduceFrame(ack, reason);
970 }
971 
WillNotReceiveBeginFrame()972 void SingleThreadProxy::WillNotReceiveBeginFrame() {
973   host_impl_->DidNotNeedBeginFrame();
974 }
975 
DidReceiveCompositorFrameAck()976 void SingleThreadProxy::DidReceiveCompositorFrameAck() {
977   layer_tree_host_->DidReceiveCompositorFrameAck();
978 }
979 
980 }  // namespace cc
981