1 // Copyright 2015 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/proxy_impl.h"
6
7 #include <string.h>
8
9 #include <algorithm>
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "base/auto_reset.h"
15 #include "base/bind.h"
16 #include "base/trace_event/trace_event.h"
17 #include "base/trace_event/traced_value.h"
18 #include "cc/base/devtools_instrumentation.h"
19 #include "cc/base/features.h"
20 #include "cc/benchmarks/benchmark_instrumentation.h"
21 #include "cc/input/browser_controls_offset_manager.h"
22 #include "cc/metrics/compositor_timing_history.h"
23 #include "cc/paint/paint_worklet_layer_painter.h"
24 #include "cc/trees/compositor_commit_data.h"
25 #include "cc/trees/layer_tree_frame_sink.h"
26 #include "cc/trees/layer_tree_host.h"
27 #include "cc/trees/layer_tree_impl.h"
28 #include "cc/trees/mutator_host.h"
29 #include "cc/trees/proxy_main.h"
30 #include "cc/trees/render_frame_metadata_observer.h"
31 #include "cc/trees/task_runner_provider.h"
32 #include "components/viz/common/frame_sinks/delay_based_time_source.h"
33 #include "components/viz/common/frame_timing_details.h"
34 #include "components/viz/common/gpu/context_provider.h"
35 #include "gpu/command_buffer/client/gles2_interface.h"
36 #include "services/metrics/public/cpp/ukm_recorder.h"
37
38 namespace cc {
39
40 namespace {
41
42 // Measured in seconds.
43 constexpr auto kSmoothnessTakesPriorityExpirationDelay =
44 base::TimeDelta::FromMilliseconds(250);
45
46 } // namespace
47
48 // Ensures that a CompletionEvent is always signaled.
49 class ScopedCompletionEvent {
50 public:
ScopedCompletionEvent(CompletionEvent * event)51 explicit ScopedCompletionEvent(CompletionEvent* event) : event_(event) {}
52 ScopedCompletionEvent(const ScopedCompletionEvent&) = delete;
~ScopedCompletionEvent()53 ~ScopedCompletionEvent() { event_->Signal(); }
54
55 ScopedCompletionEvent& operator=(const ScopedCompletionEvent&) = delete;
56
57 private:
58 CompletionEvent* const event_;
59 };
60
ProxyImpl(base::WeakPtr<ProxyMain> proxy_main_weak_ptr,LayerTreeHost * layer_tree_host,TaskRunnerProvider * task_runner_provider)61 ProxyImpl::ProxyImpl(base::WeakPtr<ProxyMain> proxy_main_weak_ptr,
62 LayerTreeHost* layer_tree_host,
63 TaskRunnerProvider* task_runner_provider)
64 : layer_tree_host_id_(layer_tree_host->GetId()),
65 commit_completion_waits_for_activation_(false),
66 next_frame_is_newly_committed_frame_(false),
67 inside_draw_(false),
68 task_runner_provider_(task_runner_provider),
69 smoothness_priority_expiration_notifier_(
70 task_runner_provider->ImplThreadTaskRunner(),
71 base::BindRepeating(&ProxyImpl::RenewTreePriority,
72 base::Unretained(this)),
73 kSmoothnessTakesPriorityExpirationDelay),
74 proxy_main_weak_ptr_(proxy_main_weak_ptr) {
75 TRACE_EVENT0("cc", "ProxyImpl::ProxyImpl");
76 DCHECK(IsImplThread());
77 DCHECK(IsMainThreadBlocked());
78
79 host_impl_ = layer_tree_host->CreateLayerTreeHostImpl(this);
80 const LayerTreeSettings& settings = layer_tree_host->GetSettings();
81 send_compositor_frame_ack_ = settings.send_compositor_frame_ack;
82 last_raster_priority_ = SAME_PRIORITY_FOR_BOTH_TREES;
83
84 SchedulerSettings scheduler_settings(settings.ToSchedulerSettings());
85
86 std::unique_ptr<CompositorTimingHistory> compositor_timing_history(
87 new CompositorTimingHistory(
88 scheduler_settings.using_synchronous_renderer_compositor,
89 CompositorTimingHistory::RENDERER_UMA,
90 layer_tree_host->rendering_stats_instrumentation(),
91 host_impl_->compositor_frame_reporting_controller()));
92 scheduler_.reset(new Scheduler(this, scheduler_settings, layer_tree_host_id_,
93 task_runner_provider_->ImplThreadTaskRunner(),
94 std::move(compositor_timing_history)));
95
96 DCHECK_EQ(scheduler_->visible(), host_impl_->visible());
97 }
98
BlockedMainCommitOnly()99 ProxyImpl::BlockedMainCommitOnly::BlockedMainCommitOnly()
100 : layer_tree_host(nullptr) {}
101
102 ProxyImpl::BlockedMainCommitOnly::~BlockedMainCommitOnly() = default;
103
~ProxyImpl()104 ProxyImpl::~ProxyImpl() {
105 TRACE_EVENT0("cc", "ProxyImpl::~ProxyImpl");
106 DCHECK(IsImplThread());
107 DCHECK(IsMainThreadBlocked());
108
109 // Prevent the scheduler from performing actions while we're in an
110 // inconsistent state.
111 scheduler_->Stop();
112 // Take away the LayerTreeFrameSink before destroying things so it doesn't
113 // try to call into its client mid-shutdown.
114 host_impl_->ReleaseLayerTreeFrameSink();
115
116 // It is important to destroy LTHI before the Scheduler since it can make
117 // callbacks that access it during destruction cleanup.
118 host_impl_ = nullptr;
119 scheduler_ = nullptr;
120
121 // We need to explicitly shutdown the notifier to destroy any weakptrs it is
122 // holding while still on the compositor thread. This also ensures any
123 // callbacks holding a ProxyImpl pointer are cancelled.
124 smoothness_priority_expiration_notifier_.Shutdown();
125 }
126
InitializeMutatorOnImpl(std::unique_ptr<LayerTreeMutator> mutator)127 void ProxyImpl::InitializeMutatorOnImpl(
128 std::unique_ptr<LayerTreeMutator> mutator) {
129 TRACE_EVENT0("cc", "ProxyImpl::InitializeMutatorOnImpl");
130 DCHECK(IsImplThread());
131 host_impl_->SetLayerTreeMutator(std::move(mutator));
132 }
133
InitializePaintWorkletLayerPainterOnImpl(std::unique_ptr<PaintWorkletLayerPainter> painter)134 void ProxyImpl::InitializePaintWorkletLayerPainterOnImpl(
135 std::unique_ptr<PaintWorkletLayerPainter> painter) {
136 TRACE_EVENT0("cc", "ProxyImpl::InitializePaintWorkletLayerPainterOnImpl");
137 DCHECK(IsImplThread());
138 host_impl_->SetPaintWorkletLayerPainter(std::move(painter));
139 }
140
UpdateBrowserControlsStateOnImpl(BrowserControlsState constraints,BrowserControlsState current,bool animate)141 void ProxyImpl::UpdateBrowserControlsStateOnImpl(
142 BrowserControlsState constraints,
143 BrowserControlsState current,
144 bool animate) {
145 DCHECK(IsImplThread());
146 host_impl_->browser_controls_manager()->UpdateBrowserControlsState(
147 constraints, current, animate);
148 }
149
InitializeLayerTreeFrameSinkOnImpl(LayerTreeFrameSink * layer_tree_frame_sink,base::WeakPtr<ProxyMain> proxy_main_frame_sink_bound_weak_ptr)150 void ProxyImpl::InitializeLayerTreeFrameSinkOnImpl(
151 LayerTreeFrameSink* layer_tree_frame_sink,
152 base::WeakPtr<ProxyMain> proxy_main_frame_sink_bound_weak_ptr) {
153 TRACE_EVENT0("cc", "ProxyImpl::InitializeLayerTreeFrameSinkOnImplThread");
154 DCHECK(IsImplThread());
155
156 proxy_main_frame_sink_bound_weak_ptr_ = proxy_main_frame_sink_bound_weak_ptr;
157
158 LayerTreeHostImpl* host_impl = host_impl_.get();
159 bool success = host_impl->InitializeFrameSink(layer_tree_frame_sink);
160 MainThreadTaskRunner()->PostTask(
161 FROM_HERE, base::BindOnce(&ProxyMain::DidInitializeLayerTreeFrameSink,
162 proxy_main_weak_ptr_, success));
163 if (success)
164 scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
165 }
166
SetDeferBeginMainFrameOnImpl(bool defer_begin_main_frame) const167 void ProxyImpl::SetDeferBeginMainFrameOnImpl(
168 bool defer_begin_main_frame) const {
169 DCHECK(IsImplThread());
170 scheduler_->SetDeferBeginMainFrame(defer_begin_main_frame);
171 }
172
SetNeedsRedrawOnImpl(const gfx::Rect & damage_rect)173 void ProxyImpl::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {
174 DCHECK(IsImplThread());
175 host_impl_->SetViewportDamage(damage_rect);
176 SetNeedsRedrawOnImplThread();
177 }
178
SetNeedsCommitOnImpl()179 void ProxyImpl::SetNeedsCommitOnImpl() {
180 DCHECK(IsImplThread());
181 SetNeedsCommitOnImplThread();
182 }
183
BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason,base::TimeTicks main_thread_start_time,std::vector<std::unique_ptr<SwapPromise>> swap_promises)184 void ProxyImpl::BeginMainFrameAbortedOnImpl(
185 CommitEarlyOutReason reason,
186 base::TimeTicks main_thread_start_time,
187 std::vector<std::unique_ptr<SwapPromise>> swap_promises) {
188 TRACE_EVENT1("cc", "ProxyImpl::BeginMainFrameAbortedOnImplThread", "reason",
189 CommitEarlyOutReasonToString(reason));
190 DCHECK(IsImplThread());
191 DCHECK(scheduler_->CommitPending());
192
193 host_impl_->BeginMainFrameAborted(
194 reason, std::move(swap_promises),
195 scheduler_->last_dispatched_begin_main_frame_args());
196 scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time);
197 scheduler_->BeginMainFrameAborted(reason);
198 }
199
SetVisibleOnImpl(bool visible)200 void ProxyImpl::SetVisibleOnImpl(bool visible) {
201 TRACE_EVENT1("cc", "ProxyImpl::SetVisibleOnImplThread", "visible", visible);
202 DCHECK(IsImplThread());
203 host_impl_->SetVisible(visible);
204 scheduler_->SetVisible(visible);
205 }
206
ReleaseLayerTreeFrameSinkOnImpl(CompletionEvent * completion)207 void ProxyImpl::ReleaseLayerTreeFrameSinkOnImpl(CompletionEvent* completion) {
208 DCHECK(IsImplThread());
209
210 // Unlike DidLoseLayerTreeFrameSinkOnImplThread, we don't need to call
211 // LayerTreeHost::DidLoseLayerTreeFrameSink since it already knows.
212 scheduler_->DidLoseLayerTreeFrameSink();
213 host_impl_->ReleaseLayerTreeFrameSink();
214 completion->Signal();
215 }
216
FinishGLOnImpl(CompletionEvent * completion)217 void ProxyImpl::FinishGLOnImpl(CompletionEvent* completion) {
218 TRACE_EVENT0("cc", "ProxyImpl::FinishGLOnImplThread");
219 DCHECK(IsImplThread());
220 if (host_impl_->layer_tree_frame_sink()) {
221 viz::ContextProvider* context_provider =
222 host_impl_->layer_tree_frame_sink()->context_provider();
223 if (context_provider)
224 context_provider->ContextGL()->Finish();
225 }
226 completion->Signal();
227 }
228
MainFrameWillHappenOnImplForTesting(CompletionEvent * completion,bool * main_frame_will_happen)229 void ProxyImpl::MainFrameWillHappenOnImplForTesting(
230 CompletionEvent* completion,
231 bool* main_frame_will_happen) {
232 DCHECK(IsImplThread());
233 if (host_impl_->layer_tree_frame_sink()) {
234 *main_frame_will_happen = scheduler_->MainFrameForTestingWillHappen();
235 } else {
236 *main_frame_will_happen = false;
237 }
238 completion->Signal();
239 }
240
RequestBeginMainFrameNotExpected(bool new_state)241 void ProxyImpl::RequestBeginMainFrameNotExpected(bool new_state) {
242 DCHECK(IsImplThread());
243 DCHECK(scheduler_);
244 TRACE_EVENT1("cc", "ProxyImpl::RequestBeginMainFrameNotExpected", "new_state",
245 new_state);
246 scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(new_state);
247 }
248
IsInSynchronousComposite() const249 bool ProxyImpl::IsInSynchronousComposite() const {
250 return false;
251 }
252
NotifyReadyToCommitOnImpl(CompletionEvent * completion,LayerTreeHost * layer_tree_host,base::TimeTicks main_thread_start_time,const viz::BeginFrameArgs & commit_args,bool hold_commit_for_activation)253 void ProxyImpl::NotifyReadyToCommitOnImpl(
254 CompletionEvent* completion,
255 LayerTreeHost* layer_tree_host,
256 base::TimeTicks main_thread_start_time,
257 const viz::BeginFrameArgs& commit_args,
258 bool hold_commit_for_activation) {
259 TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToCommitOnImpl");
260 DCHECK(!commit_completion_event_);
261 DCHECK(IsImplThread() && IsMainThreadBlocked());
262 DCHECK(scheduler_);
263 DCHECK(scheduler_->CommitPending());
264
265 if (!host_impl_) {
266 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoLayerTree",
267 TRACE_EVENT_SCOPE_THREAD);
268 completion->Signal();
269 return;
270 }
271
272 // Ideally, we should inform to impl thread when BeginMainFrame is started.
273 // But, we can avoid a PostTask in here.
274 scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time);
275
276 auto begin_main_frame_metrics = layer_tree_host->begin_main_frame_metrics();
277 host_impl_->ReadyToCommit(commit_args, begin_main_frame_metrics.get());
278
279 commit_completion_event_ =
280 std::make_unique<ScopedCompletionEvent>(completion);
281 commit_completion_waits_for_activation_ = hold_commit_for_activation;
282
283 DCHECK(!blocked_main_commit().layer_tree_host);
284 blocked_main_commit().layer_tree_host = layer_tree_host;
285
286 // Inform the layer tree host that the commit has started, so that metrics
287 // can determine how long we waited for thread synchronization.
288 layer_tree_host->SetImplCommitStartTime(base::TimeTicks::Now());
289
290 // Extract metrics data from the layer tree host and send them to the
291 // scheduler to pass them to the compositor_timing_history object.
292 scheduler_->NotifyReadyToCommit(std::move(begin_main_frame_metrics));
293 }
294
DidLoseLayerTreeFrameSinkOnImplThread()295 void ProxyImpl::DidLoseLayerTreeFrameSinkOnImplThread() {
296 TRACE_EVENT0("cc", "ProxyImpl::DidLoseLayerTreeFrameSinkOnImplThread");
297 DCHECK(IsImplThread());
298 MainThreadTaskRunner()->PostTask(
299 FROM_HERE, base::BindOnce(&ProxyMain::DidLoseLayerTreeFrameSink,
300 proxy_main_weak_ptr_));
301 scheduler_->DidLoseLayerTreeFrameSink();
302 }
303
SetBeginFrameSource(viz::BeginFrameSource * source)304 void ProxyImpl::SetBeginFrameSource(viz::BeginFrameSource* source) {
305 // During shutdown, destroying the LayerTreeFrameSink may unset the
306 // viz::BeginFrameSource.
307 if (scheduler_) {
308 // TODO(enne): this overrides any preexisting begin frame source. Those
309 // other sources will eventually be removed and this will be the only path.
310 scheduler_->SetBeginFrameSource(source);
311 }
312 }
313
DidReceiveCompositorFrameAckOnImplThread()314 void ProxyImpl::DidReceiveCompositorFrameAckOnImplThread() {
315 TRACE_EVENT0("cc,benchmark",
316 "ProxyImpl::DidReceiveCompositorFrameAckOnImplThread");
317 DCHECK(IsImplThread());
318 scheduler_->DidReceiveCompositorFrameAck();
319 if (send_compositor_frame_ack_) {
320 MainThreadTaskRunner()->PostTask(
321 FROM_HERE, base::BindOnce(&ProxyMain::DidReceiveCompositorFrameAck,
322 proxy_main_frame_sink_bound_weak_ptr_));
323 }
324 }
325
OnCanDrawStateChanged(bool can_draw)326 void ProxyImpl::OnCanDrawStateChanged(bool can_draw) {
327 TRACE_EVENT1("cc", "ProxyImpl::OnCanDrawStateChanged", "can_draw", can_draw);
328 DCHECK(IsImplThread());
329 scheduler_->SetCanDraw(can_draw);
330 }
331
NotifyReadyToActivate()332 void ProxyImpl::NotifyReadyToActivate() {
333 TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToActivate");
334 DCHECK(IsImplThread());
335 scheduler_->NotifyReadyToActivate();
336 }
337
NotifyReadyToDraw()338 void ProxyImpl::NotifyReadyToDraw() {
339 TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToDraw");
340 DCHECK(IsImplThread());
341 scheduler_->NotifyReadyToDraw();
342 }
343
SetNeedsRedrawOnImplThread()344 void ProxyImpl::SetNeedsRedrawOnImplThread() {
345 TRACE_EVENT0("cc", "ProxyImpl::SetNeedsRedrawOnImplThread");
346 DCHECK(IsImplThread());
347 scheduler_->SetNeedsRedraw();
348 }
349
SetNeedsOneBeginImplFrameOnImplThread()350 void ProxyImpl::SetNeedsOneBeginImplFrameOnImplThread() {
351 TRACE_EVENT0("cc", "ProxyImpl::SetNeedsOneBeginImplFrameOnImplThread");
352 DCHECK(IsImplThread());
353 scheduler_->SetNeedsOneBeginImplFrame();
354 }
355
SetNeedsPrepareTilesOnImplThread()356 void ProxyImpl::SetNeedsPrepareTilesOnImplThread() {
357 DCHECK(IsImplThread());
358 scheduler_->SetNeedsPrepareTiles();
359 }
360
SetNeedsCommitOnImplThread()361 void ProxyImpl::SetNeedsCommitOnImplThread() {
362 TRACE_EVENT0("cc", "ProxyImpl::SetNeedsCommitOnImplThread");
363 DCHECK(IsImplThread());
364 scheduler_->SetNeedsBeginMainFrame();
365 }
366
SetVideoNeedsBeginFrames(bool needs_begin_frames)367 void ProxyImpl::SetVideoNeedsBeginFrames(bool needs_begin_frames) {
368 TRACE_EVENT1("cc", "ProxyImpl::SetVideoNeedsBeginFrames",
369 "needs_begin_frames", needs_begin_frames);
370 DCHECK(IsImplThread());
371 // In tests the layer tree is destroyed after the scheduler is.
372 if (scheduler_)
373 scheduler_->SetVideoNeedsBeginFrames(needs_begin_frames);
374 }
375
HasCustomPropertyAnimations() const376 bool ProxyImpl::HasCustomPropertyAnimations() const {
377 return host_impl_->mutator_host()->HasCustomPropertyAnimations();
378 }
379
IsInsideDraw()380 bool ProxyImpl::IsInsideDraw() {
381 return inside_draw_;
382 }
383
IsBeginMainFrameExpected()384 bool ProxyImpl::IsBeginMainFrameExpected() {
385 // Check whether the main-thread has requested for updates. If main-thread has
386 // not responded to a previously dispatched BeginMainFrame, then assume that
387 // main-thread would want to produce an update for the current frame too.
388 return scheduler_->needs_begin_main_frame() ||
389 scheduler_->IsBeginMainFrameSent();
390 }
391
RenewTreePriority()392 void ProxyImpl::RenewTreePriority() {
393 DCHECK(IsImplThread());
394
395 bool scroll_type_considered_interaction = false;
396 bool non_scroll_interaction_in_progress =
397 host_impl_->IsPinchGestureActive() ||
398 host_impl_->page_scale_animation_active();
399
400 ActivelyScrollingType actively_scrolling_type =
401 host_impl_->GetActivelyScrollingType();
402
403 switch (actively_scrolling_type) {
404 case ActivelyScrollingType::kNone:
405 break;
406 case ActivelyScrollingType::kPrecise:
407 scroll_type_considered_interaction = true;
408 break;
409 case ActivelyScrollingType::kAnimated:
410 scroll_type_considered_interaction = base::FeatureList::IsEnabled(
411 features::kSchedulerSmoothnessForAnimatedScrolls);
412 }
413
414 bool user_interaction_in_progress =
415 non_scroll_interaction_in_progress || scroll_type_considered_interaction;
416
417 if (host_impl_->ukm_manager()) {
418 host_impl_->ukm_manager()->SetUserInteractionInProgress(
419 user_interaction_in_progress);
420 }
421
422 // Schedule expiration if smoothness currently takes priority.
423 if (user_interaction_in_progress)
424 smoothness_priority_expiration_notifier_.Schedule();
425
426 // We use the same priority for both trees by default.
427 TreePriority scheduler_tree_priority = SAME_PRIORITY_FOR_BOTH_TREES;
428 TreePriority raster_tree_priority = SAME_PRIORITY_FOR_BOTH_TREES;
429
430 // Smoothness takes priority if we have an expiration for it scheduled.
431 if (smoothness_priority_expiration_notifier_.HasPendingNotification()) {
432 scheduler_tree_priority = SMOOTHNESS_TAKES_PRIORITY;
433 if (non_scroll_interaction_in_progress ||
434 actively_scrolling_type == ActivelyScrollingType::kPrecise ||
435 last_raster_priority_ == SMOOTHNESS_TAKES_PRIORITY)
436 raster_tree_priority = SMOOTHNESS_TAKES_PRIORITY;
437 }
438
439 last_raster_priority_ = raster_tree_priority;
440
441 // New content always takes priority when ui resources have been evicted.
442 if (host_impl_->active_tree()->GetDeviceViewport().size().IsEmpty() ||
443 host_impl_->EvictedUIResourcesExist()) {
444 // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active
445 // tree might be freed. We need to set RequiresHighResToDraw to ensure that
446 // high res tiles will be required to activate pending tree.
447 host_impl_->SetRequiresHighResToDraw();
448 scheduler_tree_priority = raster_tree_priority = NEW_CONTENT_TAKES_PRIORITY;
449 }
450
451 host_impl_->SetTreePriority(raster_tree_priority);
452
453 // Only put the scheduler in impl latency prioritization mode if we don't
454 // have a scroll listener. This gives the scroll listener a better chance of
455 // handling scroll updates within the same frame. The tree itself is still
456 // kept in prefer smoothness mode to allow checkerboarding.
457 ScrollHandlerState scroll_handler_state =
458 host_impl_->ScrollAffectsScrollHandler()
459 ? ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER
460 : ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER;
461 scheduler_->SetTreePrioritiesAndScrollState(scheduler_tree_priority,
462 scroll_handler_state);
463 }
464
PostDelayedAnimationTaskOnImplThread(base::OnceClosure task,base::TimeDelta delay)465 void ProxyImpl::PostDelayedAnimationTaskOnImplThread(base::OnceClosure task,
466 base::TimeDelta delay) {
467 DCHECK(IsImplThread());
468 task_runner_provider_->ImplThreadTaskRunner()->PostDelayedTask(
469 FROM_HERE, std::move(task), delay);
470 }
471
DidActivateSyncTree()472 void ProxyImpl::DidActivateSyncTree() {
473 TRACE_EVENT0("cc", "ProxyImpl::DidActivateSyncTreeOnImplThread");
474 DCHECK(IsImplThread());
475
476 if (activation_completion_event_) {
477 TRACE_EVENT_INSTANT0("cc", "ReleaseCommitbyActivation",
478 TRACE_EVENT_SCOPE_THREAD);
479 activation_completion_event_ = nullptr;
480 }
481 }
482
WillPrepareTiles()483 void ProxyImpl::WillPrepareTiles() {
484 DCHECK(IsImplThread());
485 scheduler_->WillPrepareTiles();
486 }
487
DidPrepareTiles()488 void ProxyImpl::DidPrepareTiles() {
489 DCHECK(IsImplThread());
490 scheduler_->DidPrepareTiles();
491 }
492
DidCompletePageScaleAnimationOnImplThread()493 void ProxyImpl::DidCompletePageScaleAnimationOnImplThread() {
494 DCHECK(IsImplThread());
495 MainThreadTaskRunner()->PostTask(
496 FROM_HERE, base::BindOnce(&ProxyMain::DidCompletePageScaleAnimation,
497 proxy_main_weak_ptr_));
498 }
499
OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,bool skip_draw)500 void ProxyImpl::OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,
501 bool skip_draw) {
502 DCHECK(IsImplThread());
503 scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
504 skip_draw);
505 }
506
NeedsImplSideInvalidation(bool needs_first_draw_on_activation)507 void ProxyImpl::NeedsImplSideInvalidation(bool needs_first_draw_on_activation) {
508 DCHECK(IsImplThread());
509 scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
510 }
511
NotifyImageDecodeRequestFinished()512 void ProxyImpl::NotifyImageDecodeRequestFinished() {
513 DCHECK(IsImplThread());
514 SetNeedsCommitOnImplThread();
515 }
516
DidPresentCompositorFrameOnImplThread(uint32_t frame_token,std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,const viz::FrameTimingDetails & details)517 void ProxyImpl::DidPresentCompositorFrameOnImplThread(
518 uint32_t frame_token,
519 std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
520 const viz::FrameTimingDetails& details) {
521 MainThreadTaskRunner()->PostTask(
522 FROM_HERE,
523 base::BindOnce(&ProxyMain::DidPresentCompositorFrame,
524 proxy_main_weak_ptr_, frame_token, std::move(callbacks),
525 details.presentation_feedback));
526 if (scheduler_)
527 scheduler_->DidPresentCompositorFrame(frame_token, details);
528 }
529
NotifyAnimationWorkletStateChange(AnimationWorkletMutationState state,ElementListType element_list_type)530 void ProxyImpl::NotifyAnimationWorkletStateChange(
531 AnimationWorkletMutationState state,
532 ElementListType element_list_type) {
533 DCHECK(IsImplThread());
534 Scheduler::AnimationWorkletState animation_worklet_state =
535 (state == AnimationWorkletMutationState::STARTED)
536 ? Scheduler::AnimationWorkletState::PROCESSING
537 : Scheduler::AnimationWorkletState::IDLE;
538 Scheduler::TreeType tree_type = (element_list_type == ElementListType::ACTIVE)
539 ? Scheduler::TreeType::ACTIVE
540 : Scheduler::TreeType::PENDING;
541 scheduler_->NotifyAnimationWorkletStateChange(animation_worklet_state,
542 tree_type);
543 }
544
NotifyPaintWorkletStateChange(Scheduler::PaintWorkletState state)545 void ProxyImpl::NotifyPaintWorkletStateChange(
546 Scheduler::PaintWorkletState state) {
547 DCHECK(IsImplThread());
548 scheduler_->NotifyPaintWorkletStateChange(state);
549 }
550
NotifyThroughputTrackerResults(CustomTrackerResults results)551 void ProxyImpl::NotifyThroughputTrackerResults(CustomTrackerResults results) {
552 DCHECK(IsImplThread());
553 MainThreadTaskRunner()->PostTask(
554 FROM_HERE, base::BindOnce(&ProxyMain::NotifyThroughputTrackerResults,
555 proxy_main_weak_ptr_, std::move(results)));
556 }
557
DidObserveFirstScrollDelay(base::TimeDelta first_scroll_delay,base::TimeTicks first_scroll_timestamp)558 void ProxyImpl::DidObserveFirstScrollDelay(
559 base::TimeDelta first_scroll_delay,
560 base::TimeTicks first_scroll_timestamp) {
561 DCHECK(IsImplThread());
562 MainThreadTaskRunner()->PostTask(
563 FROM_HERE, base::BindOnce(&ProxyMain::DidObserveFirstScrollDelay,
564 proxy_main_weak_ptr_, first_scroll_delay,
565 first_scroll_timestamp));
566 }
567
WillBeginImplFrame(const viz::BeginFrameArgs & args)568 bool ProxyImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
569 DCHECK(IsImplThread());
570 return host_impl_->WillBeginImplFrame(args);
571 }
572
DidFinishImplFrame(const viz::BeginFrameArgs & last_activated_args)573 void ProxyImpl::DidFinishImplFrame(
574 const viz::BeginFrameArgs& last_activated_args) {
575 DCHECK(IsImplThread());
576 host_impl_->DidFinishImplFrame(last_activated_args);
577 }
578
DidNotProduceFrame(const viz::BeginFrameAck & ack,FrameSkippedReason reason)579 void ProxyImpl::DidNotProduceFrame(const viz::BeginFrameAck& ack,
580 FrameSkippedReason reason) {
581 DCHECK(IsImplThread());
582 host_impl_->DidNotProduceFrame(ack, reason);
583 }
584
WillNotReceiveBeginFrame()585 void ProxyImpl::WillNotReceiveBeginFrame() {
586 DCHECK(IsImplThread());
587 host_impl_->DidNotNeedBeginFrame();
588 }
589
ScheduledActionSendBeginMainFrame(const viz::BeginFrameArgs & args)590 void ProxyImpl::ScheduledActionSendBeginMainFrame(
591 const viz::BeginFrameArgs& args) {
592 DCHECK(IsImplThread());
593 benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
594 benchmark_instrumentation::kSendBeginFrame,
595 args.frame_id.sequence_number);
596 std::unique_ptr<BeginMainFrameAndCommitState> begin_main_frame_state(
597 new BeginMainFrameAndCommitState);
598 begin_main_frame_state->begin_frame_args = args;
599 begin_main_frame_state->commit_data = host_impl_->ProcessCompositorDeltas();
600 begin_main_frame_state->completed_image_decode_requests =
601 host_impl_->TakeCompletedImageDecodeRequests();
602 begin_main_frame_state->mutator_events = host_impl_->TakeMutatorEvents();
603 begin_main_frame_state->active_sequence_trackers =
604 host_impl_->FrameSequenceTrackerActiveTypes();
605 begin_main_frame_state->evicted_ui_resources =
606 host_impl_->EvictedUIResourcesExist();
607 host_impl_->WillSendBeginMainFrame();
608 MainThreadTaskRunner()->PostTask(
609 FROM_HERE,
610 base::BindOnce(&ProxyMain::BeginMainFrame, proxy_main_weak_ptr_,
611 std::move(begin_main_frame_state)));
612 host_impl_->DidSendBeginMainFrame(args);
613 devtools_instrumentation::DidRequestMainThreadFrame(layer_tree_host_id_);
614 }
615
ScheduledActionDrawIfPossible()616 DrawResult ProxyImpl::ScheduledActionDrawIfPossible() {
617 TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionDraw");
618 DCHECK(IsImplThread());
619
620 // The scheduler should never generate this call when it can't draw.
621 DCHECK(host_impl_->CanDraw());
622
623 bool forced_draw = false;
624 return DrawInternal(forced_draw);
625 }
626
ScheduledActionDrawForced()627 DrawResult ProxyImpl::ScheduledActionDrawForced() {
628 TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionDrawForced");
629 DCHECK(IsImplThread());
630 bool forced_draw = true;
631 return DrawInternal(forced_draw);
632 }
633
ScheduledActionCommit()634 void ProxyImpl::ScheduledActionCommit() {
635 TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionCommit");
636 DCHECK(IsImplThread());
637 DCHECK(IsMainThreadBlocked());
638 DCHECK(commit_completion_event_);
639
640 // Relax the cross-thread access restriction to non-thread-safe RefCount.
641 // It's safe since the main thread is blocked while a main-thread-bound
642 // compositor stuff are accessed from the impl thread.
643 base::ScopedAllowCrossThreadRefCountAccess
644 allow_cross_thread_ref_count_access;
645
646 host_impl_->BeginCommit();
647 blocked_main_commit().layer_tree_host->FinishCommitOnImplThread(
648 host_impl_.get());
649
650 // Remove the LayerTreeHost reference before the completion event is signaled
651 // and cleared. This is necessary since blocked_main_commit() allows access
652 // only while we have the completion event to ensure the main thread is
653 // blocked for a commit.
654 blocked_main_commit().layer_tree_host = nullptr;
655
656 if (commit_completion_waits_for_activation_) {
657 // For some layer types in impl-side painting, the commit is held until the
658 // sync tree is activated. It's also possible that the sync tree has
659 // already activated if there was no work to be done.
660 TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD);
661 commit_completion_waits_for_activation_ = false;
662 activation_completion_event_ = std::move(commit_completion_event_);
663 }
664 commit_completion_event_ = nullptr;
665
666 scheduler_->DidCommit();
667
668 // Delay this step until afer the main thread has been released as it's
669 // often a good bit of work to update the tree and prepare the new frame.
670 host_impl_->CommitComplete();
671
672 next_frame_is_newly_committed_frame_ = true;
673 }
674
ScheduledActionActivateSyncTree()675 void ProxyImpl::ScheduledActionActivateSyncTree() {
676 TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionActivateSyncTree");
677 DCHECK(IsImplThread());
678 host_impl_->ActivateSyncTree();
679 }
680
ScheduledActionBeginLayerTreeFrameSinkCreation()681 void ProxyImpl::ScheduledActionBeginLayerTreeFrameSinkCreation() {
682 TRACE_EVENT0("cc",
683 "ProxyImpl::ScheduledActionBeginLayerTreeFrameSinkCreation");
684 DCHECK(IsImplThread());
685 MainThreadTaskRunner()->PostTask(
686 FROM_HERE, base::BindOnce(&ProxyMain::RequestNewLayerTreeFrameSink,
687 proxy_main_weak_ptr_));
688 }
689
ScheduledActionPrepareTiles()690 void ProxyImpl::ScheduledActionPrepareTiles() {
691 TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionPrepareTiles");
692 DCHECK(IsImplThread());
693 host_impl_->PrepareTiles();
694 }
695
ScheduledActionInvalidateLayerTreeFrameSink(bool needs_redraw)696 void ProxyImpl::ScheduledActionInvalidateLayerTreeFrameSink(bool needs_redraw) {
697 TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionInvalidateLayerTreeFrameSink");
698 DCHECK(IsImplThread());
699 host_impl_->InvalidateLayerTreeFrameSink(needs_redraw);
700 }
701
ScheduledActionPerformImplSideInvalidation()702 void ProxyImpl::ScheduledActionPerformImplSideInvalidation() {
703 TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionPerformImplSideInvalidation");
704 DCHECK(IsImplThread());
705 host_impl_->InvalidateContentOnImplSide();
706 }
707
SendBeginMainFrameNotExpectedSoon()708 void ProxyImpl::SendBeginMainFrameNotExpectedSoon() {
709 DCHECK(IsImplThread());
710 MainThreadTaskRunner()->PostTask(
711 FROM_HERE, base::BindOnce(&ProxyMain::BeginMainFrameNotExpectedSoon,
712 proxy_main_weak_ptr_));
713 }
714
ScheduledActionBeginMainFrameNotExpectedUntil(base::TimeTicks time)715 void ProxyImpl::ScheduledActionBeginMainFrameNotExpectedUntil(
716 base::TimeTicks time) {
717 DCHECK(IsImplThread());
718 MainThreadTaskRunner()->PostTask(
719 FROM_HERE, base::BindOnce(&ProxyMain::BeginMainFrameNotExpectedUntil,
720 proxy_main_weak_ptr_, time));
721 }
722
DrawInternal(bool forced_draw)723 DrawResult ProxyImpl::DrawInternal(bool forced_draw) {
724 DCHECK(IsImplThread());
725 DCHECK(host_impl_.get());
726
727 base::AutoReset<bool> mark_inside(&inside_draw_, true);
728
729 // This method is called on a forced draw, regardless of whether we are able
730 // to produce a frame, as the calling site on main thread is blocked until its
731 // request completes, and we signal completion here. If CanDraw() is false, we
732 // will indicate success=false to the caller, but we must still signal
733 // completion to avoid deadlock.
734
735 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
736 // frame, so can only be used when such a frame is possible. Since
737 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
738 // CanDraw() as well.
739
740 LayerTreeHostImpl::FrameData frame;
741 frame.begin_frame_ack = scheduler_->CurrentBeginFrameAckForActiveTree();
742 frame.origin_begin_main_frame_args =
743 scheduler_->last_activate_origin_frame_args();
744 bool draw_frame = false;
745
746 DrawResult result;
747 if (host_impl_->CanDraw()) {
748 result = host_impl_->PrepareToDraw(&frame);
749 draw_frame = forced_draw || result == DRAW_SUCCESS;
750 } else {
751 result = DRAW_ABORTED_CANT_DRAW;
752 }
753
754 if (draw_frame) {
755 if (host_impl_->DrawLayers(&frame)) {
756 DCHECK_NE(frame.frame_token, 0u);
757 // Drawing implies we submitted a frame to the LayerTreeFrameSink.
758 scheduler_->DidSubmitCompositorFrame(frame.frame_token,
759 host_impl_->TakeEventsMetrics());
760 }
761 result = DRAW_SUCCESS;
762 } else {
763 DCHECK_NE(DRAW_SUCCESS, result);
764 }
765
766 host_impl_->DidDrawAllLayers(frame);
767
768 bool start_ready_animations = draw_frame;
769 host_impl_->UpdateAnimationState(start_ready_animations);
770
771 // Tell the main thread that the newly-commited frame was drawn.
772 if (next_frame_is_newly_committed_frame_) {
773 next_frame_is_newly_committed_frame_ = false;
774 MainThreadTaskRunner()->PostTask(
775 FROM_HERE, base::BindOnce(&ProxyMain::DidCommitAndDrawFrame,
776 proxy_main_weak_ptr_));
777 }
778
779 // The tile visibility/priority of the pending tree needs to be updated so
780 // that it doesn't get activated before the raster is complete. But this needs
781 // to happen after the draw, off of the critical path to draw.
782 if (host_impl_->pending_tree())
783 host_impl_->pending_tree()->UpdateDrawProperties();
784
785 DCHECK_NE(INVALID_RESULT, result);
786 return result;
787 }
788
IsImplThread() const789 bool ProxyImpl::IsImplThread() const {
790 return task_runner_provider_->IsImplThread();
791 }
792
IsMainThreadBlocked() const793 bool ProxyImpl::IsMainThreadBlocked() const {
794 return task_runner_provider_->IsMainThreadBlocked();
795 }
796
blocked_main_commit()797 ProxyImpl::BlockedMainCommitOnly& ProxyImpl::blocked_main_commit() {
798 DCHECK(IsMainThreadBlocked() && commit_completion_event_);
799 return main_thread_blocked_commit_vars_unsafe_;
800 }
801
MainThreadTaskRunner()802 base::SingleThreadTaskRunner* ProxyImpl::MainThreadTaskRunner() {
803 return task_runner_provider_->MainThreadTaskRunner();
804 }
805
SetSourceURL(ukm::SourceId source_id,const GURL & url)806 void ProxyImpl::SetSourceURL(ukm::SourceId source_id, const GURL& url) {
807 DCHECK(IsImplThread());
808 host_impl_->SetActiveURL(url, source_id);
809 }
810
SetUkmSmoothnessDestination(base::WritableSharedMemoryMapping ukm_smoothness_data)811 void ProxyImpl::SetUkmSmoothnessDestination(
812 base::WritableSharedMemoryMapping ukm_smoothness_data) {
813 DCHECK(IsImplThread());
814 host_impl_->SetUkmSmoothnessDestination(std::move(ukm_smoothness_data));
815 }
816
ClearHistory()817 void ProxyImpl::ClearHistory() {
818 DCHECK(IsImplThread());
819 DCHECK(IsMainThreadBlocked());
820 scheduler_->ClearHistory();
821 }
822
SetRenderFrameObserver(std::unique_ptr<RenderFrameMetadataObserver> observer)823 void ProxyImpl::SetRenderFrameObserver(
824 std::unique_ptr<RenderFrameMetadataObserver> observer) {
825 host_impl_->SetRenderFrameObserver(std::move(observer));
826 }
827
SetEnableFrameRateThrottling(bool enable_frame_rate_throttling)828 void ProxyImpl::SetEnableFrameRateThrottling(
829 bool enable_frame_rate_throttling) {
830 host_impl_->SetEnableFrameRateThrottling(enable_frame_rate_throttling);
831 }
832
833 } // namespace cc
834