forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlayer_tree_host_impl.cc
5150 lines (4446 loc) · 202 KB
/
layer_tree_host_impl.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/trees/layer_tree_host_impl.h"
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <limits>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/containers/adapters.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/metrics/histogram.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/trace_event/traced_value.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "cc/base/devtools_instrumentation.h"
#include "cc/base/features.h"
#include "cc/base/histograms.h"
#include "cc/base/math_util.h"
#include "cc/base/switches.h"
#include "cc/benchmarks/benchmark_instrumentation.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/document_transition/document_transition_request.h"
#include "cc/input/browser_controls_offset_manager.h"
#include "cc/input/page_scale_animation.h"
#include "cc/input/scrollbar_animation_controller.h"
#include "cc/input/scroller_size_metrics.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/effect_tree_layer_list_iterator.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/layers/surface_layer_impl.h"
#include "cc/layers/viewport.h"
#include "cc/metrics/compositor_frame_reporting_controller.h"
#include "cc/metrics/frame_sequence_metrics.h"
#include "cc/metrics/lcd_text_metrics_reporter.h"
#include "cc/metrics/ukm_smoothness_data.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_worklet_job.h"
#include "cc/paint/paint_worklet_layer_painter.h"
#include "cc/raster/bitmap_raster_buffer_provider.h"
#include "cc/raster/gpu_raster_buffer_provider.h"
#include "cc/raster/one_copy_raster_buffer_provider.h"
#include "cc/raster/raster_buffer_provider.h"
#include "cc/raster/synchronous_task_graph_runner.h"
#include "cc/raster/zero_copy_raster_buffer_provider.h"
#include "cc/resources/memory_history.h"
#include "cc/resources/resource_pool.h"
#include "cc/resources/ui_resource_bitmap.h"
#include "cc/tiles/eviction_tile_priority_queue.h"
#include "cc/tiles/frame_viewer_instrumentation.h"
#include "cc/tiles/gpu_image_decode_cache.h"
#include "cc/tiles/picture_layer_tiling.h"
#include "cc/tiles/raster_tile_priority_queue.h"
#include "cc/tiles/software_image_decode_cache.h"
#include "cc/tiles/tiles_with_resource_iterator.h"
#include "cc/trees/compositor_commit_data.h"
#include "cc/trees/damage_tracker.h"
#include "cc/trees/debug_rect_history.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/image_animation_controller.h"
#include "cc/trees/latency_info_swap_promise_monitor.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/mobile_optimized_viewport_util.h"
#include "cc/trees/mutator_host.h"
#include "cc/trees/presentation_time_callback_buffer.h"
#include "cc/trees/render_frame_metadata.h"
#include "cc/trees/render_frame_metadata_observer.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_timing_details.h"
#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
#include "components/viz/common/quads/frame_deadline.h"
#include "components/viz/common/quads/shared_quad_state.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/resources/bitmap_allocation.h"
#include "components/viz/common/resources/platform_color.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/traced_value.h"
#include "components/viz/common/transition_utils.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_latency_info.pbzero.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace cc {
namespace {
// In BuildHitTestData we iterate all layers to find all layers that overlap
// OOPIFs, but when the number of layers is greater than
// |kAssumeOverlapThreshold|, it can be inefficient to accumulate layer bounds
// for overlap checking. As a result, we are conservative and make OOPIFs
// kHitTestAsk after the threshold is reached.
const size_t kAssumeOverlapThreshold = 100;
// gfx::DisplayColorSpaces stores up to 3 different color spaces. This should be
// updated to match any size changes in DisplayColorSpaces.
constexpr size_t kContainsSrgbCacheSize = 3;
static_assert(kContainsSrgbCacheSize ==
gfx::DisplayColorSpaces::kConfigCount / 2,
"sRGB cache must match the size of DisplayColorSpaces");
bool IsMobileOptimized(LayerTreeImpl* active_tree) {
return util::IsMobileOptimized(active_tree->min_page_scale_factor(),
active_tree->max_page_scale_factor(),
active_tree->current_page_scale_factor(),
active_tree->ScrollableViewportSize(),
active_tree->ScrollableSize(),
active_tree->viewport_mobile_optimized());
}
viz::ResourceFormat TileRasterBufferFormat(
const LayerTreeSettings& settings,
viz::ContextProvider* context_provider,
bool use_gpu_rasterization) {
// Software compositing always uses the native skia RGBA N32 format, but we
// just call it RGBA_8888 everywhere even though it can be BGRA ordering,
// because we don't need to communicate the actual ordering as the code all
// assumes the native skia format.
if (!context_provider)
return viz::RGBA_8888;
// RGBA4444 overrides the defaults if specified, but only for gpu compositing.
// It is always supported on platforms where it is specified.
if (settings.use_rgba_4444)
return viz::RGBA_4444;
// Otherwise we use BGRA textures if we can but it depends on the context
// capabilities, and we have different preferences when rastering to textures
// vs uploading textures.
const gpu::Capabilities& caps = context_provider->ContextCapabilities();
if (use_gpu_rasterization)
return viz::PlatformColor::BestSupportedRenderBufferFormat(caps);
return viz::PlatformColor::BestSupportedTextureFormat(caps);
}
void DidVisibilityChange(LayerTreeHostImpl* id, bool visible) {
if (visible) {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
"cc,benchmark", "LayerTreeHostImpl::SetVisible", TRACE_ID_LOCAL(id),
"LayerTreeHostImpl", static_cast<void*>(id));
return;
}
TRACE_EVENT_NESTABLE_ASYNC_END0(
"cc,benchmark", "LayerTreeHostImpl::SetVisible", TRACE_ID_LOCAL(id));
}
void PopulateMetadataContentColorUsage(
const LayerTreeHostImpl::FrameData* frame,
viz::CompositorFrameMetadata* metadata) {
metadata->content_color_usage = gfx::ContentColorUsage::kSRGB;
for (const LayerImpl* layer : frame->will_draw_layers) {
metadata->content_color_usage =
std::max(metadata->content_color_usage, layer->GetContentColorUsage());
}
}
// Registers callbacks, as needed, to track First Scroll Latency.
void ApplyFirstScrollTracking(const ui::LatencyInfo* latency,
uint32_t frame_token,
LayerTreeHostImpl* impl) {
base::TimeTicks creation_timestamp;
// If |latency| isn't tracking a scroll, we don't need to do extra
// first-scroll tracking.
auto scroll_update_started =
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT;
auto scroll_update_continued =
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT;
if (!latency->FindLatency(scroll_update_started, &creation_timestamp) &&
!latency->FindLatency(scroll_update_continued, &creation_timestamp)) {
return;
}
// Construct a callback that, given a successful presentation timestamp, will
// report the time span between the scroll input-event creation and the
// presentation timestamp.
PresentationTimeCallbackBuffer::CompositorCallback presentation_callback =
base::BindOnce(
[](base::TimeTicks event_creation,
LayerTreeHostImpl* layer_tree_host_impl,
base::TimeTicks presentation_timestamp) {
layer_tree_host_impl->DidObserveScrollDelay(
presentation_timestamp - event_creation, event_creation);
},
creation_timestamp, impl);
// Tell the |LayerTreeHostImpl| to run our callback with the presentation
// feedback corresponding to the given |frame_token|.
impl->RegisterCompositorPresentationTimeCallback(
frame_token, std::move(presentation_callback));
}
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class SourceIdConsistency : int {
kConsistent = 0,
kContainsInvalid = 1,
kNonUnique = 2,
kInvalidAndNonUnique = 3,
kMaxValue = kInvalidAndNonUnique,
};
void RecordSourceIdConsistency(bool all_valid, bool all_unique) {
SourceIdConsistency consistency =
all_unique ? (all_valid ? SourceIdConsistency::kConsistent
: SourceIdConsistency::kContainsInvalid)
: (all_valid ? SourceIdConsistency::kNonUnique
: SourceIdConsistency::kInvalidAndNonUnique);
// TODO(crbug.com/1062764): we're sometimes seeing unexpected values for the
// ukm::SourceId. We'll use this histogram to track how often it happens so
// we can properly (de-)prioritize a fix.
UMA_HISTOGRAM_ENUMERATION("Event.LatencyInfo.Debug.SourceIdConsistency",
consistency);
}
// Dump verbose log with
// --vmodule=layer_tree_host_impl=3 for renderer only, or
// --vmodule=layer_tree_host_impl=4 for all clients.
bool VerboseLogEnabled() {
if (!VLOG_IS_ON(3))
return false;
if (VLOG_IS_ON(4))
return true;
const char* client_name = GetClientNameForMetrics();
return client_name && strcmp(client_name, "Renderer") == 0;
}
const char* ClientNameForVerboseLog() {
const char* client_name = GetClientNameForMetrics();
return client_name ? client_name : "<unknown client>";
}
#define VERBOSE_LOG() \
VLOG_IF(3, VerboseLogEnabled()) << ClientNameForVerboseLog() << ": "
} // namespace
void LayerTreeHostImpl::DidUpdateScrollAnimationCurve() {
// Because we updated the animation target, notify the
// `LatencyInfoSwapPromiseMonitor` to tell it that something happened that
// will cause a swap in the future. This will happen within the scope of the
// dispatch of a gesture scroll update input event. If we don't notify during
// the handling of the input event, the `LatencyInfo` associated with the
// input event will not be added as a swap promise and we won't get any swap
// results.
NotifyLatencyInfoSwapPromiseMonitors();
events_metrics_manager_.SaveActiveEventMetrics();
}
void LayerTreeHostImpl::AccumulateScrollDeltaForTracing(
const gfx::Vector2dF& delta) {
scroll_accumulated_this_frame_ += delta;
}
void LayerTreeHostImpl::DidStartPinchZoom() {
client_->RenewTreePriority();
frame_trackers_.StartSequence(FrameSequenceTrackerType::kPinchZoom);
}
void LayerTreeHostImpl::DidEndPinchZoom() {
// When a pinch ends, we may be displaying content cached at incorrect scales,
// so updating draw properties and drawing will ensure we are using the right
// scales that we want when we're not inside a pinch.
active_tree_->set_needs_update_draw_properties();
SetNeedsRedraw();
frame_trackers_.StopSequence(FrameSequenceTrackerType::kPinchZoom);
}
void LayerTreeHostImpl::DidUpdatePinchZoom() {
SetNeedsRedraw();
client_->RenewTreePriority();
}
void LayerTreeHostImpl::DidStartScroll() {
scroll_affects_scroll_handler_ = active_tree()->have_scroll_event_handlers();
client_->RenewTreePriority();
}
void LayerTreeHostImpl::DidEndScroll() {
scroll_affects_scroll_handler_ = false;
current_scroll_did_checkerboard_large_area_ = false;
}
void LayerTreeHostImpl::DidMouseLeave() {
for (auto& pair : scrollbar_animation_controllers_)
pair.second->DidMouseLeave();
}
void LayerTreeHostImpl::SetNeedsFullViewportRedraw() {
// TODO(bokan): Do these really need to be manually called? (Rather than
// damage/redraw being set from scroll offset changes).
SetFullViewportDamage();
SetNeedsRedraw();
}
void LayerTreeHostImpl::SetDeferBeginMainFrame(
bool defer_begin_main_frame) const {
client_->SetDeferBeginMainFrameFromImpl(defer_begin_main_frame);
}
bool LayerTreeHostImpl::IsInHighLatencyMode() const {
return impl_thread_phase_ == ImplThreadPhase::IDLE;
}
const LayerTreeSettings& LayerTreeHostImpl::GetSettings() const {
return settings();
}
LayerTreeHostImpl& LayerTreeHostImpl::GetImplDeprecated() {
return *this;
}
const LayerTreeHostImpl& LayerTreeHostImpl::GetImplDeprecated() const {
return *this;
}
bool LayerTreeHostImpl::CanInjectJankOnMain() const {
return !!frame_trackers_.FrameSequenceTrackerActiveTypes() &&
compositor_frame_reporting_controller_
->is_main_thread_driving_smoothness();
}
LayerTreeHostImpl::FrameData::FrameData() = default;
LayerTreeHostImpl::FrameData::~FrameData() = default;
LayerTreeHostImpl::UIResourceData::UIResourceData() = default;
LayerTreeHostImpl::UIResourceData::~UIResourceData() = default;
LayerTreeHostImpl::UIResourceData::UIResourceData(UIResourceData&&) noexcept =
default;
LayerTreeHostImpl::UIResourceData& LayerTreeHostImpl::UIResourceData::operator=(
UIResourceData&&) = default;
std::unique_ptr<LayerTreeHostImpl> LayerTreeHostImpl::Create(
const LayerTreeSettings& settings,
LayerTreeHostImplClient* client,
TaskRunnerProvider* task_runner_provider,
RenderingStatsInstrumentation* rendering_stats_instrumentation,
TaskGraphRunner* task_graph_runner,
std::unique_ptr<MutatorHost> mutator_host,
RasterDarkModeFilter* dark_mode_filter,
int id,
scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner,
LayerTreeHostSchedulingClient* scheduling_client) {
return base::WrapUnique(new LayerTreeHostImpl(
settings, client, task_runner_provider, rendering_stats_instrumentation,
task_graph_runner, std::move(mutator_host), dark_mode_filter, id,
std::move(image_worker_task_runner), scheduling_client));
}
LayerTreeHostImpl::LayerTreeHostImpl(
const LayerTreeSettings& settings,
LayerTreeHostImplClient* client,
TaskRunnerProvider* task_runner_provider,
RenderingStatsInstrumentation* rendering_stats_instrumentation,
TaskGraphRunner* task_graph_runner,
std::unique_ptr<MutatorHost> mutator_host,
RasterDarkModeFilter* dark_mode_filter,
int id,
scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner,
LayerTreeHostSchedulingClient* scheduling_client)
: client_(client),
scheduling_client_(scheduling_client),
task_runner_provider_(task_runner_provider),
current_begin_frame_tracker_(FROM_HERE),
settings_(settings),
is_synchronous_single_threaded_(!task_runner_provider->HasImplThread() &&
!settings_.single_thread_proxy_scheduler),
cached_managed_memory_policy_(settings.memory_policy),
// Must be initialized after is_synchronous_single_threaded_ and
// task_runner_provider_.
tile_manager_(this,
GetTaskRunner(),
std::move(image_worker_task_runner),
is_synchronous_single_threaded_
? std::numeric_limits<size_t>::max()
: settings.scheduled_raster_task_limit,
settings.ToTileManagerSettings()),
memory_history_(MemoryHistory::Create()),
debug_rect_history_(DebugRectHistory::Create()),
mutator_host_(std::move(mutator_host)),
dark_mode_filter_(dark_mode_filter),
rendering_stats_instrumentation_(rendering_stats_instrumentation),
micro_benchmark_controller_(this),
task_graph_runner_(task_graph_runner),
id_(id),
consecutive_frame_with_damage_count_(settings.damaged_frame_limit),
// It is safe to use base::Unretained here since we will outlive the
// ImageAnimationController.
image_animation_controller_(GetTaskRunner(),
this,
settings_.enable_image_animation_resync),
compositor_frame_reporting_controller_(
std::make_unique<CompositorFrameReportingController>(
/*should_report_histograms=*/!settings
.single_thread_proxy_scheduler,
/*should_report_ukm=*/!settings.single_thread_proxy_scheduler,
id)),
frame_trackers_(settings.single_thread_proxy_scheduler,
compositor_frame_reporting_controller_.get()),
lcd_text_metrics_reporter_(LCDTextMetricsReporter::CreateIfNeeded(this)),
frame_rate_estimator_(GetTaskRunner()),
contains_srgb_cache_(kContainsSrgbCacheSize) {
DCHECK(mutator_host_);
mutator_host_->SetMutatorHostClient(this);
mutator_events_ = mutator_host_->CreateEvents();
DCHECK(task_runner_provider_->IsImplThread());
DidVisibilityChange(this, visible_);
// LTHI always has an active tree.
active_tree_ = std::make_unique<LayerTreeImpl>(
*this, new SyncedScale, new SyncedBrowserControls,
new SyncedBrowserControls, new SyncedElasticOverscroll);
active_tree_->property_trees()->set_is_active(true);
viewport_ = Viewport::Create(this);
TRACE_EVENT_OBJECT_CREATED_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"cc::LayerTreeHostImpl", id_);
browser_controls_offset_manager_ = BrowserControlsOffsetManager::Create(
this, settings.top_controls_show_threshold,
settings.top_controls_hide_threshold);
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableLayerTreeHostMemoryPressure)) {
memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
FROM_HERE, base::BindRepeating(&LayerTreeHostImpl::OnMemoryPressure,
base::Unretained(this)));
}
SetDebugState(settings.initial_debug_state);
compositor_frame_reporting_controller_->SetDroppedFrameCounter(
&dropped_frame_counter_);
compositor_frame_reporting_controller_->SetFrameSequenceTrackerCollection(
&frame_trackers_);
const bool is_ui = settings.is_layer_tree_for_ui;
if (is_ui) {
compositor_frame_reporting_controller_->set_event_latency_tracker(this);
#if BUILDFLAG(IS_CHROMEOS)
dropped_frame_counter_.EnableReporForUI();
compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
FrameInfo::SmoothEffectDrivingThread::kMain, true);
#endif // BUILDFLAG(IS_CHROMEOS)
}
dropped_frame_counter_.set_total_counter(&total_frame_counter_);
frame_trackers_.set_custom_tracker_results_added_callback(
base::BindRepeating(&LayerTreeHostImpl::NotifyThroughputTrackerResults,
weak_factory_.GetWeakPtr()));
}
LayerTreeHostImpl::~LayerTreeHostImpl() {
DCHECK(task_runner_provider_->IsImplThread());
TRACE_EVENT0("cc", "LayerTreeHostImpl::~LayerTreeHostImpl()");
TRACE_EVENT_OBJECT_DELETED_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"cc::LayerTreeHostImpl", id_);
// The frame sink is released before shutdown, which takes down
// all the resource and raster structures.
DCHECK(!layer_tree_frame_sink_);
DCHECK(!resource_pool_);
DCHECK(!image_decode_cache_);
DCHECK(!single_thread_synchronous_task_graph_runner_);
if (input_delegate_)
input_delegate_->WillShutdown();
// The layer trees must be destroyed before the LayerTreeHost. Also, if they
// are holding onto any resources, destroying them will release them, before
// we mark any leftover resources as lost.
if (recycle_tree_)
recycle_tree_->Shutdown();
if (pending_tree_)
pending_tree_->Shutdown();
active_tree_->Shutdown();
recycle_tree_ = nullptr;
pending_tree_ = nullptr;
active_tree_ = nullptr;
// All resources should already be removed, so lose anything still exported.
resource_provider_.ShutdownAndReleaseAllResources();
mutator_host_->ClearMutators();
mutator_host_->SetMutatorHostClient(nullptr);
// Clear the UKM Manager so that we do not try to report when the
// UKM System has shut down.
compositor_frame_reporting_controller_->SetUkmManager(nullptr);
// `frame_trackers_` holds a pointer to
// `compositor_frame_reporting_controller_`. Setting
// `compositor_frame_reporting_controller_` to nullptr here leads to
// `frame_trackers_` holding a dangling ptr. Don't set to null here and let
// members be destroyed in reverse order of declaration.
// Since `frame_trackers_` is destroyed first, we need to clear the ptr that
// `compositor_frame_reporting_controller_` holds.
compositor_frame_reporting_controller_->SetFrameSequenceTrackerCollection(
nullptr);
}
InputHandler& LayerTreeHostImpl::GetInputHandler() {
DCHECK(input_delegate_) << "Requested InputHandler when one wasn't bound. "
"Call BindToInputHandler to bind to one";
return static_cast<InputHandler&>(*input_delegate_.get());
}
const InputHandler& LayerTreeHostImpl::GetInputHandler() const {
DCHECK(input_delegate_) << "Requested InputHandler when one wasn't bound. "
"Call BindToInputHandler to bind to one";
return static_cast<const InputHandler&>(*input_delegate_.get());
}
void LayerTreeHostImpl::DidSendBeginMainFrame(const viz::BeginFrameArgs& args) {
frame_trackers_.NotifyBeginMainFrame(args);
}
void LayerTreeHostImpl::BeginMainFrameAborted(
CommitEarlyOutReason reason,
std::vector<std::unique_ptr<SwapPromise>> swap_promises,
const viz::BeginFrameArgs& args,
bool scroll_and_viewport_changes_synced) {
if (reason == CommitEarlyOutReason::ABORTED_NOT_VISIBLE ||
reason == CommitEarlyOutReason::FINISHED_NO_UPDATES) {
frame_trackers_.NotifyMainFrameCausedNoDamage(args, true);
} else {
frame_trackers_.NotifyMainFrameProcessed(args);
}
// If the begin frame data was handled, then scroll and scale set was applied
// by the main thread, so the active tree needs to be updated as if these sent
// values were applied and committed.
bool main_frame_applied_deltas = MainFrameAppliedDeltas(reason);
active_tree_->ApplySentScrollAndScaleDeltasFromAbortedCommit(
main_frame_applied_deltas);
if (main_frame_applied_deltas) {
if (pending_tree_) {
pending_tree_->AppendSwapPromises(std::move(swap_promises));
} else {
for (const auto& swap_promise : swap_promises) {
SwapPromise::DidNotSwapAction action =
swap_promise->DidNotSwap(SwapPromise::COMMIT_NO_UPDATE);
DCHECK_EQ(action, SwapPromise::DidNotSwapAction::BREAK_PROMISE);
}
}
}
// Notify the browser controls manager that we have processed any
// controls constraint update.
if (scroll_and_viewport_changes_synced && browser_controls_manager()) {
browser_controls_manager()->NotifyConstraintSyncedToMainThread();
}
}
void LayerTreeHostImpl::ReadyToCommit(
const viz::BeginFrameArgs& commit_args,
const BeginMainFrameMetrics* begin_main_frame_metrics,
bool commit_timeout) {
frame_trackers_.NotifyMainFrameProcessed(commit_args);
if (!is_measuring_smoothness_ &&
((begin_main_frame_metrics &&
begin_main_frame_metrics->should_measure_smoothness) ||
commit_timeout)) {
is_measuring_smoothness_ = true;
total_frame_counter_.Reset();
dropped_frame_counter_.OnFcpReceived();
}
// Notify the browser controls manager that we have processed any
// controls constraint update.
if (browser_controls_manager()) {
browser_controls_manager()->NotifyConstraintSyncedToMainThread();
}
}
void LayerTreeHostImpl::BeginCommit(int source_frame_number,
uint64_t trace_id) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::BeginCommit");
if (!CommitToActiveTree())
CreatePendingTree();
sync_tree()->set_source_frame_number(source_frame_number);
sync_tree()->set_trace_id(trace_id);
}
// This function commits the LayerTreeHost, as represented by CommitState, to an
// impl tree. When modifying this function -- and all code that it calls into
// -- care must be taken to avoid using LayerTreeHost directly (e.g., via
// state.root_layer->layer_tree_host()) as that will likely introduce thread
// safety violations. Any information that is needed from LayerTreeHost should
// instead be plumbed through CommitState (see
// LayerTreeHost::ActivateCommitState() for reference).
void LayerTreeHostImpl::FinishCommit(
CommitState& state,
const ThreadUnsafeCommitState& unsafe_state) {
TRACE_EVENT0("cc,benchmark", "LayerTreeHostImpl::FinishCommit");
LayerTreeImpl* tree = sync_tree();
tree->PullPropertiesFrom(state, unsafe_state);
PullLayerTreeHostPropertiesFrom(state);
// Transfer image decode requests to the impl thread.
for (auto& entry : state.queued_image_decodes)
QueueImageDecode(entry.first, *entry.second);
for (auto& benchmark : state.benchmarks)
ScheduleMicroBenchmark(std::move(benchmark));
// Dump property trees and layers if VerboseLogEnabled().
VERBOSE_LOG() << "After finishing commit on impl, the sync tree:"
<< "\nproperty_trees:\n"
<< tree->property_trees()->ToString() << "\n"
<< "cc::LayerImpls:\n"
<< tree->LayerListAsJson();
}
void LayerTreeHostImpl::PullLayerTreeHostPropertiesFrom(
const CommitState& commit_state) {
// TODO(bokan): The |external_pinch_gesture_active| should not be going
// through the LayerTreeHost but directly from InputHandler to InputHandler.
SetExternalPinchGestureActive(commit_state.is_external_pinch_gesture_active);
if (commit_state.needs_gpu_rasterization_histogram)
RecordGpuRasterizationHistogram();
SetDebugState(commit_state.debug_state);
SetVisualDeviceViewportSize(commit_state.visual_device_viewport_size);
set_viewport_mobile_optimized(commit_state.is_viewport_mobile_optimized);
SetPrefersReducedMotion(commit_state.prefers_reduced_motion);
SetMayThrottleIfUndrawnFrames(commit_state.may_throttle_if_undrawn_frames);
}
void LayerTreeHostImpl::RecordGpuRasterizationHistogram() {
bool gpu_rasterization_enabled = false;
if (layer_tree_frame_sink()) {
viz::ContextProvider* compositor_context_provider =
layer_tree_frame_sink()->context_provider();
if (compositor_context_provider) {
gpu_rasterization_enabled =
compositor_context_provider->ContextCapabilities().gpu_rasterization;
}
}
// Record how widely gpu rasterization is enabled.
// This number takes device/gpu allowlist/denylist into account.
// Note that we do not consider the forced gpu rasterization mode, which is
// mostly used for debugging purposes.
UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationEnabled",
gpu_rasterization_enabled);
}
void LayerTreeHostImpl::CommitComplete() {
TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete");
if (input_delegate_)
input_delegate_->DidCommit();
if (CommitToActiveTree()) {
active_tree_->HandleScrollbarShowRequests();
// We have to activate animations here or "IsActive()" is true on the layers
// but the animations aren't activated yet so they get ignored by
// UpdateDrawProperties.
ActivateAnimations();
}
// We clear the entries that were never mutated by CC animations from the last
// commit until now. Moreover, we reset the values of input properties and
// relies on the fact that CC animation will mutate those values when pending
// tree is animated below.
// With that, when CC finishes animating an input property, the value of that
// property stays at finish state until a commit kicks in, which is consistent
// with current composited animations.
paint_worklet_tracker_.ClearUnusedInputProperties();
// Start animations before UpdateDrawProperties and PrepareTiles, as they can
// change the results. When doing commit to the active tree, this must happen
// after ActivateAnimations() in order for this ticking to be propagated
// to layers on the active tree.
if (CommitToActiveTree())
Animate();
else
AnimatePendingTreeAfterCommit();
UpdateSyncTreeAfterCommitOrImplSideInvalidation();
micro_benchmark_controller_.DidCompleteCommit();
if (mutator_host_->CurrentFrameHadRAF())
frame_trackers_.StartSequence(FrameSequenceTrackerType::kRAF);
if (mutator_host_->HasCanvasInvalidation())
frame_trackers_.StartSequence(FrameSequenceTrackerType::kCanvasAnimation);
if (mutator_host_->CurrentFrameHadRAF() || mutator_host_->HasJSAnimation())
frame_trackers_.StartSequence(FrameSequenceTrackerType::kJSAnimation);
if (mutator_host_->MainThreadAnimationsCount() > 0 ||
mutator_host_->HasSmilAnimation()) {
frame_trackers_.StartSequence(
FrameSequenceTrackerType::kMainThreadAnimation);
if (mutator_host_->HasSharedElementTransition()) {
frame_trackers_.StartSequence(
FrameSequenceTrackerType::kSETMainThreadAnimation);
}
}
for (const auto& info : mutator_host_->TakePendingThroughputTrackerInfos()) {
const MutatorHost::TrackedAnimationSequenceId sequence_id = info.id;
const bool start = info.start;
if (start)
frame_trackers_.StartCustomSequence(sequence_id);
else
frame_trackers_.StopCustomSequence(sequence_id);
}
}
void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
// LayerTreeHost may have changed the GPU rasterization flags state, which
// may require an update of the tree resources.
UpdateTreeResourcesForGpuRasterizationIfNeeded();
sync_tree()->set_needs_update_draw_properties();
// We need an update immediately post-commit to have the opportunity to create
// tilings.
// We can avoid updating the ImageAnimationController during this
// DrawProperties update since it will be done when we animate the controller
// below.
bool update_image_animation_controller = false;
sync_tree()->UpdateDrawProperties(update_image_animation_controller);
// Defer invalidating images until UpdateDrawProperties is performed since
// that updates whether an image should be animated based on its visibility
// and the updated data for the image from the main frame.
PaintImageIdFlatSet images_to_invalidate =
tile_manager_.TakeImagesToInvalidateOnSyncTree();
const auto& animated_images =
image_animation_controller_.AnimateForSyncTree(CurrentBeginFrameArgs());
images_to_invalidate.insert(animated_images.begin(), animated_images.end());
// Invalidate cached PaintRecords for worklets whose input properties were
// mutated since the last pending tree. We keep requesting invalidations until
// the animation is ticking on impl thread. Note that this works since the
// animation starts ticking on the pending tree
// (AnimatePendingTreeAfterCommit) which committed this animation timeline.
// After this the animation may only tick on the active tree for impl-side
// invalidations (since AnimatePendingTreeAfterCommit is not done for pending
// trees created by impl-side invalidations). But we ensure here that we
// request another invalidation if an input property was mutated on the active
// tree.
if (paint_worklet_tracker_.InvalidatePaintWorkletsOnPendingTree()) {
client_->NeedsImplSideInvalidation(
true /* needs_first_draw_on_activation */);
}
PaintImageIdFlatSet dirty_paint_worklet_ids;
PaintWorkletJobMap dirty_paint_worklets =
GatherDirtyPaintWorklets(&dirty_paint_worklet_ids);
images_to_invalidate.insert(dirty_paint_worklet_ids.begin(),
dirty_paint_worklet_ids.end());
sync_tree()->InvalidateRegionForImages(images_to_invalidate);
// Note that it is important to push the state for checkerboarded and animated
// images prior to PrepareTiles here when committing to the active tree. This
// is because new tiles on the active tree depend on tree specific state
// cached in these components, which must be pushed to active before preparing
// tiles for the updated active tree.
if (CommitToActiveTree())
ActivateStateForImages();
if (!paint_worklet_painter_) {
// Blink should not send us any PaintWorklet inputs until we have a painter
// registered.
DCHECK(sync_tree()->picture_layers_with_paint_worklets().empty());
pending_tree_fully_painted_ = true;
NotifyPendingTreeFullyPainted();
return;
}
if (!dirty_paint_worklets.size()) {
pending_tree_fully_painted_ = true;
NotifyPendingTreeFullyPainted();
return;
}
client_->NotifyPaintWorkletStateChange(
Scheduler::PaintWorkletState::PROCESSING);
auto done_callback = base::BindOnce(
&LayerTreeHostImpl::OnPaintWorkletResultsReady, base::Unretained(this));
paint_worklet_painter_->DispatchWorklets(std::move(dirty_paint_worklets),
std::move(done_callback));
}
PaintWorkletJobMap LayerTreeHostImpl::GatherDirtyPaintWorklets(
PaintImageIdFlatSet* dirty_paint_worklet_ids) const {
PaintWorkletJobMap dirty_paint_worklets;
for (PictureLayerImpl* layer :
sync_tree()->picture_layers_with_paint_worklets()) {
for (const auto& entry : layer->GetPaintWorkletRecordMap()) {
const scoped_refptr<const PaintWorkletInput>& input = entry.first;
const PaintImage::Id& paint_image_id = entry.second.first;
const sk_sp<PaintRecord>& record = entry.second.second;
// If we already have a record we can reuse it and so the
// PaintWorkletInput isn't dirty.
if (record)
continue;
// Mark this PaintWorklet as needing invalidation.
dirty_paint_worklet_ids->insert(paint_image_id);
// Create an entry in the appropriate PaintWorkletJobVector for this dirty
// PaintWorklet.
int worklet_id = input->WorkletId();
auto& job_vector = dirty_paint_worklets[worklet_id];
if (!job_vector)
job_vector = base::MakeRefCounted<PaintWorkletJobVector>();
PaintWorkletJob::AnimatedPropertyValues animated_property_values;
for (const auto& element : input->GetPropertyKeys()) {
DCHECK(!animated_property_values.contains(element));
const PaintWorkletInput::PropertyValue& animated_property_value =
paint_worklet_tracker_.GetPropertyAnimationValue(element);
// No value indicates that the input property was not mutated by CC
// animation.
if (animated_property_value.has_value())
animated_property_values.emplace(element, animated_property_value);
}
job_vector->data.emplace_back(layer->id(), input,
std::move(animated_property_values));
}
}
return dirty_paint_worklets;
}
void LayerTreeHostImpl::OnPaintWorkletResultsReady(PaintWorkletJobMap results) {
#if DCHECK_IS_ON()
// Nothing else should have painted the PaintWorklets while we were waiting,
// and the results should have painted every PaintWorklet, so these should be
// the same.
PaintImageIdFlatSet dirty_paint_worklet_ids;
DCHECK_EQ(results.size(),
GatherDirtyPaintWorklets(&dirty_paint_worklet_ids).size());
#endif
for (const auto& entry : results) {
for (const PaintWorkletJob& job : entry.second->data) {
LayerImpl* layer_impl =
pending_tree_->FindPendingTreeLayerById(job.layer_id());
// Painting the pending tree occurs asynchronously but stalls the pending
// tree pipeline, so nothing should have changed while we were doing that.
DCHECK(layer_impl);
static_cast<PictureLayerImpl*>(layer_impl)
->SetPaintWorkletRecord(job.input(), job.output());
}
}
// While the pending tree is being painted by PaintWorklets, we restrict the
// tiles the TileManager is able to see. This may cause the TileManager to
// believe that it has finished rastering all the necessary tiles. When we
// finish painting the tree and release all the tiles, we need to mark the
// tile priorities as dirty so that the TileManager logic properly re-runs.
tile_priorities_dirty_ = true;
// Set the painted state before calling the scheduler, to ensure any callback
// running as a result sees the correct painted state.
pending_tree_fully_painted_ = true;
client_->NotifyPaintWorkletStateChange(Scheduler::PaintWorkletState::IDLE);
// The pending tree may have been force activated from the signal to the
// scheduler above, in which case there is no longer a tree to paint.
if (pending_tree_)
NotifyPendingTreeFullyPainted();
}
void LayerTreeHostImpl::NotifyPendingTreeFullyPainted() {
// The pending tree must be fully painted at this point.
DCHECK(pending_tree_fully_painted_);
// Nobody should claim the pending tree is fully painted if there is an
// ongoing dispatch.
DCHECK(!paint_worklet_painter_ ||
!paint_worklet_painter_->HasOngoingDispatch());
// Start working on newly created tiles immediately if needed.
// TODO(vmpstr): Investigate always having PrepareTiles issue
// NotifyReadyToActivate, instead of handling it here.
bool did_prepare_tiles = PrepareTiles();
if (!did_prepare_tiles) {
NotifyReadyToActivate();
// Ensure we get ReadyToDraw signal even when PrepareTiles not run. This
// is important for SingleThreadProxy and impl-side painting case. For
// STP, we commit to active tree and RequiresHighResToDraw, and set
// Scheduler to wait for ReadyToDraw signal to avoid Checkerboard.
if (CommitToActiveTree())
NotifyReadyToDraw();
}
}
bool LayerTreeHostImpl::CanDraw() const {
// Note: If you are changing this function or any other function that might
// affect the result of CanDraw, make sure to call
// client_->OnCanDrawStateChanged in the proper places and update the
// NotifyIfCanDrawChanged test.
if (!layer_tree_frame_sink_) {
TRACE_EVENT_INSTANT0("cc",
"LayerTreeHostImpl::CanDraw no LayerTreeFrameSink",
TRACE_EVENT_SCOPE_THREAD);
return false;
}
// TODO(boliu): Make draws without layers work and move this below
// |resourceless_software_draw_| check. Tracked in crbug.com/264967.
if (active_tree_->LayerListIsEmpty()) {
TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::CanDraw no root layer",
TRACE_EVENT_SCOPE_THREAD);
return false;
}
if (resourceless_software_draw_)
return true;
if (active_tree_->GetDeviceViewport().IsEmpty()) {
TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::CanDraw empty viewport",
TRACE_EVENT_SCOPE_THREAD);
return false;
}
if (EvictedUIResourcesExist()) {
TRACE_EVENT_INSTANT0(
"cc", "LayerTreeHostImpl::CanDraw UI resources evicted not recreated",
TRACE_EVENT_SCOPE_THREAD);
return false;
}
return true;
}
void LayerTreeHostImpl::AnimatePendingTreeAfterCommit() {
// Animate the pending tree layer animations to put them at initial positions
// and starting state. There is no need to run other animations on pending
// tree because they depend on user inputs so the state is identical to what
// the active tree has.
AnimateLayers(CurrentBeginFrameArgs().frame_time, /* is_active_tree */ false);
}
void LayerTreeHostImpl::Animate() {
AnimateInternal();
}
void LayerTreeHostImpl::AnimateInternal() {
DCHECK(task_runner_provider_->IsImplThread());
base::TimeTicks monotonic_time = CurrentBeginFrameArgs().frame_time;
// mithro(TODO): Enable these checks.
// DCHECK(!current_begin_frame_tracker_.HasFinished());
// DCHECK(monotonic_time == current_begin_frame_tracker_.Current().frame_time)
// << "Called animate with unknown frame time!?";
bool did_animate = false;
// TODO(bokan): This should return did_animate, see TODO in