summaryrefslogtreecommitdiff
path: root/chromium/cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 10:22:43 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 12:36:28 +0000
commit271a6c3487a14599023a9106329505597638d793 (patch)
treee040d58ffc86c1480b79ca8528020ca9ec919bf8 /chromium/cc
parent7b2ffa587235a47d4094787d72f38102089f402a (diff)
downloadqtwebengine-chromium-271a6c3487a14599023a9106329505597638d793.tar.gz
BASELINE: Update Chromium to 77.0.3865.59
Change-Id: I1e89a5f3b009a9519a6705102ad65c92fe736f21 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn38
-rw-r--r--chromium/cc/DEPS3
-rw-r--r--chromium/cc/README.md2
-rw-r--r--chromium/cc/animation/DEPS1
-rw-r--r--chromium/cc/animation/animation.h2
-rw-r--r--chromium/cc/animation/animation_events.h2
-rw-r--r--chromium/cc/animation/animation_host.cc17
-rw-r--r--chromium/cc/animation/animation_host.h9
-rw-r--r--chromium/cc/animation/element_animations.h2
-rw-r--r--chromium/cc/animation/keyframe_effect.cc2
-rw-r--r--chromium/cc/animation/keyframe_effect.h2
-rw-r--r--chromium/cc/animation/keyframe_model.cc19
-rw-r--r--chromium/cc/animation/keyframe_model.h19
-rw-r--r--chromium/cc/animation/keyframe_model_unittest.cc14
-rw-r--r--chromium/cc/animation/keyframed_animation_curve.cc4
-rw-r--r--chromium/cc/animation/keyframed_animation_curve.h5
-rw-r--r--chromium/cc/animation/keyframed_animation_curve_unittest.cc21
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve.cc24
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve.h11
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve_unittest.cc35
-rw-r--r--chromium/cc/animation/scroll_offset_animations_impl.cc29
-rw-r--r--chromium/cc/animation/scroll_offset_animations_impl.h10
-rw-r--r--chromium/cc/animation/scroll_timeline.h2
-rw-r--r--chromium/cc/animation/single_keyframe_effect_animation.h2
-rw-r--r--chromium/cc/animation/timing_function.cc60
-rw-r--r--chromium/cc/animation/timing_function.h36
-rw-r--r--chromium/cc/base/delayed_unique_notifier.cc3
-rw-r--r--chromium/cc/base/delayed_unique_notifier.h2
-rw-r--r--chromium/cc/base/devtools_instrumentation.cc3
-rw-r--r--chromium/cc/base/devtools_instrumentation.h5
-rw-r--r--chromium/cc/base/rolling_time_delta_history.cc7
-rw-r--r--chromium/cc/base/rolling_time_delta_history.h1
-rw-r--r--chromium/cc/base/unique_notifier.cc3
-rw-r--r--chromium/cc/base/unique_notifier.h2
-rw-r--r--chromium/cc/benchmarks/micro_benchmark_impl.cc2
-rw-r--r--chromium/cc/benchmarks/rasterize_and_record_benchmark.cc3
-rw-r--r--chromium/cc/benchmarks/rasterize_and_record_benchmark.h2
-rw-r--r--chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc6
-rw-r--r--chromium/cc/benchmarks/unittest_only_benchmark.cc4
-rw-r--r--chromium/cc/benchmarks/unittest_only_benchmark.h2
-rw-r--r--chromium/cc/debug/debug_colors.cc19
-rw-r--r--chromium/cc/debug/debug_colors.h4
-rw-r--r--chromium/cc/input/input_handler.h10
-rw-r--r--chromium/cc/input/scroll_state.h2
-rw-r--r--chromium/cc/input/scrollbar.h12
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.cc6
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.h2
-rw-r--r--chromium/cc/input/scrollbar_controller.cc197
-rw-r--r--chromium/cc/input/scrollbar_controller.h39
-rw-r--r--chromium/cc/layers/append_quads_data.h5
-rw-r--r--chromium/cc/layers/draw_properties.cc5
-rw-r--r--chromium/cc/layers/draw_properties.h8
-rw-r--r--chromium/cc/layers/heads_up_display_layer.cc1
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc47
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.h8
-rw-r--r--chromium/cc/layers/layer.cc135
-rw-r--r--chromium/cc/layers/layer.h46
-rw-r--r--chromium/cc/layers/layer_impl.cc84
-rw-r--r--chromium/cc/layers/layer_impl.h47
-rw-r--r--chromium/cc/layers/layer_impl_test_properties.h1
-rw-r--r--chromium/cc/layers/layer_impl_unittest.cc26
-rw-r--r--chromium/cc/layers/layer_sticky_position_constraint.h4
-rw-r--r--chromium/cc/layers/layer_unittest.cc331
-rw-r--r--chromium/cc/layers/mirror_layer.cc49
-rw-r--r--chromium/cc/layers/mirror_layer.h42
-rw-r--r--chromium/cc/layers/mirror_layer_impl.cc92
-rw-r--r--chromium/cc/layers/mirror_layer_impl.h63
-rw-r--r--chromium/cc/layers/mirror_layer_unittest.cc141
-rw-r--r--chromium/cc/layers/nine_patch_generator.cc2
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc2
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.cc20
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.cc6
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_unittest.cc6
-rw-r--r--chromium/cc/layers/picture_layer.cc13
-rw-r--r--chromium/cc/layers/picture_layer.h2
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc279
-rw-r--r--chromium/cc/layers/picture_layer_impl.h56
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc100
-rw-r--r--chromium/cc/layers/render_surface_impl.cc215
-rw-r--r--chromium/cc/layers/render_surface_impl.h5
-rw-r--r--chromium/cc/layers/render_surface_impl_unittest.cc3
-rw-r--r--chromium/cc/layers/render_surface_unittest.cc91
-rw-r--r--chromium/cc/layers/scrollbar_layer_unittest.cc18
-rw-r--r--chromium/cc/layers/surface_layer_impl.cc2
-rw-r--r--chromium/cc/layers/texture_layer.cc3
-rw-r--r--chromium/cc/layers/texture_layer.h7
-rw-r--r--chromium/cc/layers/texture_layer_impl.cc5
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc12
-rw-r--r--chromium/cc/layers/tile_size_calculator.cc221
-rw-r--r--chromium/cc/layers/tile_size_calculator.h50
-rw-r--r--chromium/cc/layers/touch_action_region.cc23
-rw-r--r--chromium/cc/layers/touch_action_region.h9
-rw-r--r--chromium/cc/layers/touch_action_region_unittest.cc20
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl.cc2
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc26
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h9
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc16
-rw-r--r--chromium/cc/paint/BUILD.gn8
-rw-r--r--chromium/cc/paint/DEPS12
-rw-r--r--chromium/cc/paint/discardable_image_map.cc32
-rw-r--r--chromium/cc/paint/discardable_image_map.h7
-rw-r--r--chromium/cc/paint/discardable_image_map_unittest.cc46
-rw-r--r--chromium/cc/paint/display_item_list.cc10
-rw-r--r--chromium/cc/paint/display_item_list.h5
-rw-r--r--chromium/cc/paint/element_id.cc (renamed from chromium/cc/trees/element_id.cc)4
-rw-r--r--chromium/cc/paint/element_id.h (renamed from chromium/cc/trees/element_id.h)19
-rw-r--r--chromium/cc/paint/image_provider.cc9
-rw-r--r--chromium/cc/paint/image_provider.h2
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.cc421
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.h73
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry_unittest.cc328
-rw-r--r--chromium/cc/paint/node_holder.cc51
-rw-r--r--chromium/cc/paint/node_holder.h47
-rw-r--r--chromium/cc/paint/node_id.h22
-rw-r--r--chromium/cc/paint/oop_pixeltest.cc14
-rw-r--r--chromium/cc/paint/paint_canvas.h7
-rw-r--r--chromium/cc/paint/paint_flags.cc1
-rw-r--r--chromium/cc/paint/paint_flags.h11
-rw-r--r--chromium/cc/paint/paint_image.h4
-rw-r--r--chromium/cc/paint/paint_image_unittest.cc14
-rw-r--r--chromium/cc/paint/paint_op_buffer.cc62
-rw-r--r--chromium/cc/paint/paint_op_buffer.h16
-rw-r--r--chromium/cc/paint/paint_op_buffer_unittest.cc9
-rw-r--r--chromium/cc/paint/paint_op_reader.cc26
-rw-r--r--chromium/cc/paint/paint_op_reader.h1
-rw-r--r--chromium/cc/paint/paint_op_writer.cc8
-rw-r--r--chromium/cc/paint/paint_op_writer.h2
-rw-r--r--chromium/cc/paint/paint_worklet_input.h14
-rw-r--r--chromium/cc/paint/paint_worklet_job.cc24
-rw-r--r--chromium/cc/paint/paint_worklet_job.h59
-rw-r--r--chromium/cc/paint/paint_worklet_layer_painter.h24
-rw-r--r--chromium/cc/paint/record_paint_canvas.cc6
-rw-r--r--chromium/cc/paint/record_paint_canvas.h4
-rw-r--r--chromium/cc/paint/skia_paint_canvas.cc61
-rw-r--r--chromium/cc/paint/skia_paint_canvas.h4
-rw-r--r--chromium/cc/paint/text_holder.h30
-rw-r--r--chromium/cc/paint/transfer_cache_unittest.cc4
-rw-r--r--chromium/cc/raster/bitmap_raster_buffer_provider.cc9
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.cc10
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.h24
-rw-r--r--chromium/cc/raster/one_copy_raster_buffer_provider.cc3
-rw-r--r--chromium/cc/raster/paint_worklet_image_provider.cc19
-rw-r--r--chromium/cc/raster/paint_worklet_image_provider.h19
-rw-r--r--chromium/cc/raster/raster_buffer_provider.cc2
-rw-r--r--chromium/cc/raster/raster_source.cc11
-rw-r--r--chromium/cc/raster/raster_source.h5
-rw-r--r--chromium/cc/raster/raster_source_unittest.cc57
-rw-r--r--chromium/cc/raster/single_thread_task_graph_runner.cc3
-rw-r--r--chromium/cc/raster/staging_buffer_pool.cc3
-rw-r--r--chromium/cc/raster/staging_buffer_pool.h2
-rw-r--r--chromium/cc/raster/synchronous_task_graph_runner.cc1
-rw-r--r--chromium/cc/raster/task_graph_work_queue.cc4
-rw-r--r--chromium/cc/raster/zero_copy_raster_buffer_provider.cc2
-rw-r--r--chromium/cc/resources/resource_pool.cc3
-rw-r--r--chromium/cc/resources/resource_pool.h2
-rw-r--r--chromium/cc/scheduler/compositor_frame_reporter.cc207
-rw-r--r--chromium/cc/scheduler/compositor_frame_reporter.h102
-rw-r--r--chromium/cc/scheduler/compositor_frame_reporter_unittest.cc298
-rw-r--r--chromium/cc/scheduler/compositor_frame_reporting_controller.cc160
-rw-r--r--chromium/cc/scheduler/compositor_frame_reporting_controller.h34
-rw-r--r--chromium/cc/scheduler/compositor_frame_reporting_controller_unittest.cc96
-rw-r--r--chromium/cc/scheduler/compositor_timing_history.cc27
-rw-r--r--chromium/cc/scheduler/compositor_timing_history.h7
-rw-r--r--chromium/cc/scheduler/scheduler.cc53
-rw-r--r--chromium/cc/scheduler/scheduler.h39
-rw-r--r--chromium/cc/scheduler/scheduler_settings.cc10
-rw-r--r--chromium/cc/scheduler/scheduler_settings.h26
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.cc74
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.h29
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine_unittest.cc94
-rw-r--r--chromium/cc/scheduler/scheduler_unittest.cc155
-rw-r--r--chromium/cc/tiles/checker_image_tracker.cc3
-rw-r--r--chromium/cc/tiles/checker_image_tracker.h2
-rw-r--r--chromium/cc/tiles/decoded_image_tracker.cc3
-rw-r--r--chromium/cc/tiles/decoded_image_tracker.h2
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.cc364
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.h61
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_perftest.cc11
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_unittest.cc1369
-rw-r--r--chromium/cc/tiles/image_controller.cc42
-rw-r--r--chromium/cc/tiles/image_controller.h32
-rw-r--r--chromium/cc/tiles/image_controller_unittest.cc28
-rw-r--r--chromium/cc/tiles/image_decode_cache.cc8
-rw-r--r--chromium/cc/tiles/image_decode_cache.h3
-rw-r--r--chromium/cc/tiles/paint_worklet_image_cache.cc146
-rw-r--r--chromium/cc/tiles/paint_worklet_image_cache.h87
-rw-r--r--chromium/cc/tiles/paint_worklet_image_cache_unittest.cc261
-rw-r--r--chromium/cc/tiles/picture_layer_tiling.h8
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set.cc2
-rw-r--r--chromium/cc/tiles/prioritized_tile.h4
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.cc38
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.h16
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_utils.h11
-rw-r--r--chromium/cc/tiles/tile_manager.cc30
-rw-r--r--chromium/cc/tiles/tile_manager.h8
-rw-r--r--chromium/cc/tiles/tile_manager_unittest.cc2
-rw-r--r--chromium/cc/tiles/tile_task_manager.cc6
-rw-r--r--chromium/cc/trees/damage_tracker.cc4
-rw-r--r--chromium/cc/trees/damage_tracker_unittest.cc81
-rw-r--r--chromium/cc/trees/draw_property_utils.cc24
-rw-r--r--chromium/cc/trees/draw_property_utils.h3
-rw-r--r--chromium/cc/trees/effect_node.cc6
-rw-r--r--chromium/cc/trees/effect_node.h7
-rw-r--r--chromium/cc/trees/frame_sequence_tracker.cc390
-rw-r--r--chromium/cc/trees/frame_sequence_tracker.h238
-rw-r--r--chromium/cc/trees/frame_sequence_tracker_unittest.cc109
-rw-r--r--chromium/cc/trees/image_animation_controller.cc2
-rw-r--r--chromium/cc/trees/image_animation_controller.h2
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink.cc3
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink.h5
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink_client.h3
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink_unittest.cc3
-rw-r--r--chromium/cc/trees/layer_tree_host.cc32
-rw-r--r--chromium/cc/trees/layer_tree_host.h15
-rw-r--r--chromium/cc/trees/layer_tree_host_client.h14
-rw-r--r--chromium/cc/trees/layer_tree_host_common.cc14
-rw-r--r--chromium/cc/trees/layer_tree_host_common.h8
-rw-r--r--chromium/cc/trees/layer_tree_host_common_perftest.cc1
-rw-r--r--chromium/cc/trees/layer_tree_host_common_unittest.cc371
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc454
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h105
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc354
-rw-r--r--chromium/cc/trees/layer_tree_host_perftest.cc6
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_blending.cc68
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_filters.cc233
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_masks.cc194
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_mirror.cc83
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_readback.cc91
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc29
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc11
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc44
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc418
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_animation.cc17
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_capture_content.cc107
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc2
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_context.cc6
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc10
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_masks.cc195
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_picture.cc8
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_scroll.cc228
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc65
-rw-r--r--chromium/cc/trees/layer_tree_impl.h21
-rw-r--r--chromium/cc/trees/layer_tree_impl_unittest.cc68
-rw-r--r--chromium/cc/trees/layer_tree_settings.cc8
-rw-r--r--chromium/cc/trees/layer_tree_settings.h4
-rw-r--r--chromium/cc/trees/mutator_host.h9
-rw-r--r--chromium/cc/trees/mutator_host_client.h2
-rw-r--r--chromium/cc/trees/occlusion_tracker_unittest.cc1
-rw-r--r--chromium/cc/trees/property_tree.cc30
-rw-r--r--chromium/cc/trees/property_tree.h3
-rw-r--r--chromium/cc/trees/property_tree_builder.cc77
-rw-r--r--chromium/cc/trees/proxy.h4
-rw-r--r--chromium/cc/trees/proxy_impl.cc36
-rw-r--r--chromium/cc/trees/proxy_impl.h3
-rw-r--r--chromium/cc/trees/proxy_main.cc61
-rw-r--r--chromium/cc/trees/proxy_main.h5
-rw-r--r--chromium/cc/trees/scroll_node.cc2
-rw-r--r--chromium/cc/trees/scroll_node.h2
-rw-r--r--chromium/cc/trees/single_thread_proxy.cc46
-rw-r--r--chromium/cc/trees/single_thread_proxy.h8
-rw-r--r--chromium/cc/trees/transform_node.h5
-rw-r--r--chromium/cc/trees/tree_synchronizer.cc6
-rw-r--r--chromium/cc/trees/tree_synchronizer_unittest.cc28
-rw-r--r--chromium/cc/trees/viewport_layers.h3
264 files changed, 8940 insertions, 4258 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
index b0fde3505e6..80c2ef7647c 100644
--- a/chromium/cc/BUILD.gn
+++ b/chromium/cc/BUILD.gn
@@ -88,6 +88,10 @@ cc_component("cc") {
"layers/layer_position_constraint.h",
"layers/layer_sticky_position_constraint.cc",
"layers/layer_sticky_position_constraint.h",
+ "layers/mirror_layer.cc",
+ "layers/mirror_layer.h",
+ "layers/mirror_layer_impl.cc",
+ "layers/mirror_layer_impl.h",
"layers/nine_patch_generator.cc",
"layers/nine_patch_generator.h",
"layers/nine_patch_layer.cc",
@@ -132,6 +136,8 @@ cc_component("cc") {
"layers/texture_layer_client.h",
"layers/texture_layer_impl.cc",
"layers/texture_layer_impl.h",
+ "layers/tile_size_calculator.cc",
+ "layers/tile_size_calculator.h",
"layers/touch_action_region.cc",
"layers/touch_action_region.h",
"layers/ui_resource_layer.cc",
@@ -234,8 +240,6 @@ cc_component("cc") {
"tiles/image_decode_cache_utils.h",
"tiles/mipmap_util.cc",
"tiles/mipmap_util.h",
- "tiles/paint_worklet_image_cache.cc",
- "tiles/paint_worklet_image_cache.h",
"tiles/picture_layer_tiling.cc",
"tiles/picture_layer_tiling.h",
"tiles/picture_layer_tiling_set.cc",
@@ -284,10 +288,10 @@ cc_component("cc") {
"trees/draw_property_utils.h",
"trees/effect_node.cc",
"trees/effect_node.h",
- "trees/element_id.cc",
- "trees/element_id.h",
"trees/frame_rate_counter.cc",
"trees/frame_rate_counter.h",
+ "trees/frame_sequence_tracker.cc",
+ "trees/frame_sequence_tracker.h",
"trees/image_animation_controller.cc",
"trees/image_animation_controller.h",
"trees/latency_info_swap_promise.cc",
@@ -502,10 +506,8 @@ cc_test_static_library("test_support") {
"test/task_graph_runner_test_template.h",
"test/test_hooks.cc",
"test/test_hooks.h",
- "test/test_image_factory.cc",
- "test/test_image_factory.h",
- "test/test_in_process_context_provider.cc",
- "test/test_in_process_context_provider.h",
+ "test/test_layer_tree_frame_sink.cc",
+ "test/test_layer_tree_frame_sink.h",
"test/test_layer_tree_host_base.cc",
"test/test_layer_tree_host_base.h",
"test/test_occlusion_tracker.h",
@@ -605,6 +607,7 @@ cc_test("cc_unittests") {
"layers/layer_list_iterator_unittest.cc",
"layers/layer_position_constraint_unittest.cc",
"layers/layer_unittest.cc",
+ "layers/mirror_layer_unittest.cc",
"layers/nine_patch_generator_unittest.cc",
"layers/nine_patch_layer_impl_unittest.cc",
"layers/nine_patch_layer_unittest.cc",
@@ -634,6 +637,7 @@ cc_test("cc_unittests") {
"paint/discardable_image_map_unittest.cc",
"paint/display_item_list_unittest.cc",
"paint/filter_operations_unittest.cc",
+ "paint/image_transfer_cache_entry_unittest.cc",
"paint/oop_pixeltest.cc",
"paint/paint_cache_unittest.cc",
"paint/paint_filter_unittest.cc",
@@ -654,6 +658,7 @@ cc_test("cc_unittests") {
"raster/synchronous_task_graph_runner_unittest.cc",
"raster/task_graph_work_queue_unittest.cc",
"resources/resource_pool_unittest.cc",
+ "scheduler/compositor_frame_reporter_unittest.cc",
"scheduler/compositor_frame_reporting_controller_unittest.cc",
"scheduler/compositor_timing_history_unittest.cc",
"scheduler/scheduler_state_machine_unittest.cc",
@@ -664,7 +669,6 @@ cc_test("cc_unittests") {
"tiles/gpu_image_decode_cache_unittest.cc",
"tiles/image_controller_unittest.cc",
"tiles/mipmap_util_unittest.cc",
- "tiles/paint_worklet_image_cache_unittest.cc",
"tiles/picture_layer_tiling_set_unittest.cc",
"tiles/picture_layer_tiling_unittest.cc",
"tiles/software_image_decode_cache_unittest.cc",
@@ -672,6 +676,7 @@ cc_test("cc_unittests") {
"tiles/tile_manager_unittest.cc",
"tiles/tile_priority_unittest.cc",
"trees/damage_tracker_unittest.cc",
+ "trees/frame_sequence_tracker_unittest.cc",
"trees/image_animation_controller_unittest.cc",
"trees/layer_tree_frame_sink_unittest.cc",
"trees/layer_tree_host_common_unittest.cc",
@@ -679,6 +684,7 @@ cc_test("cc_unittests") {
"trees/layer_tree_host_pixeltest_blending.cc",
"trees/layer_tree_host_pixeltest_filters.cc",
"trees/layer_tree_host_pixeltest_masks.cc",
+ "trees/layer_tree_host_pixeltest_mirror.cc",
"trees/layer_tree_host_pixeltest_readback.cc",
"trees/layer_tree_host_pixeltest_scrollbars.cc",
"trees/layer_tree_host_pixeltest_synchronous.cc",
@@ -771,6 +777,20 @@ cc_test("cc_unittests") {
data_deps = [
"//third_party/mesa_headers",
]
+
+ if (enable_vulkan) {
+ deps += [
+ "//gpu/vulkan:test_support",
+ "//gpu/vulkan/init",
+ ]
+
+ # TODO(samans): Support more configurations.
+ # CFI issue: https://crbug.com/967819
+ # LSAN issue: https://crbug.com/971325
+ if (use_x11 && !is_cfi && !is_lsan) {
+ defines = [ "ENABLE_CC_VULKAN_TESTS" ]
+ }
+ }
}
cc_test("cc_perftests") {
diff --git a/chromium/cc/DEPS b/chromium/cc/DEPS
index 0186be319b6..8d3576c0da9 100644
--- a/chromium/cc/DEPS
+++ b/chromium/cc/DEPS
@@ -22,6 +22,7 @@ include_rules = [
"+gpu/command_buffer/common/sync_token.h",
"+gpu/command_buffer/common/texture_in_use_response.h",
"+gpu/config/gpu_feature_info.h",
+ "+gpu/config/gpu_finch_features.h",
"+gpu/vulkan",
"+media",
"+mojo/public/cpp/system/buffer.h",
@@ -58,6 +59,8 @@ specific_include_rules = {
".*_(unit|pixel|perf)test.*\.cc": [
"+components/viz/service/display",
"+components/viz/test",
+ "+gpu/command_buffer/common/command_buffer_id.h",
+ "+gpu/command_buffer/common/constants.h",
],
"oop_pixeltest\.cc" : [
"+gpu/command_buffer/client",
diff --git a/chromium/cc/README.md b/chromium/cc/README.md
index 4c51342f0e8..e8ae01d7bfb 100644
--- a/chromium/cc/README.md
+++ b/chromium/cc/README.md
@@ -71,7 +71,7 @@ RenderPass has been drawn to.
Chosen by cc's clients and can be used as a stable identifier across updates.
For example, blink uses ElementIDs as a stable id for the object (opaque to cc)
that is responsible for a composited animation. Some additional information in
-[element_id.h](https://codesearch.chromium.org/chromium/src/cc/trees/element_id.h)
+[element_id.h](https://codesearch.chromium.org/chromium/src/cc/paint/element_id.h)
### DirectRenderer
An abstraction that provides an API for the Display to draw a fully-aggregated
diff --git a/chromium/cc/animation/DEPS b/chromium/cc/animation/DEPS
index bc229ac9da9..808b4349b0b 100644
--- a/chromium/cc/animation/DEPS
+++ b/chromium/cc/animation/DEPS
@@ -8,7 +8,6 @@ include_rules = [
"+cc/test",
"+cc/trees/animation_options.h",
"+cc/trees/animation_effect_timings.h",
- "+cc/trees/element_id.h",
"+cc/trees/mutator_host.h",
"+cc/trees/mutator_host_client.h",
"+cc/trees/property_animation_state.h",
diff --git a/chromium/cc/animation/animation.h b/chromium/cc/animation/animation.h
index 14a988505a9..12ad6058cdc 100644
--- a/chromium/cc/animation/animation.h
+++ b/chromium/cc/animation/animation.h
@@ -14,7 +14,7 @@
#include "cc/animation/animation_export.h"
#include "cc/animation/element_animations.h"
#include "cc/animation/keyframe_model.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
namespace cc {
diff --git a/chromium/cc/animation/animation_events.h b/chromium/cc/animation/animation_events.h
index 6e3fed34d34..584292197ae 100644
--- a/chromium/cc/animation/animation_events.h
+++ b/chromium/cc/animation/animation_events.h
@@ -11,8 +11,8 @@
#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/keyframe_model.h"
+#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
-#include "cc/trees/element_id.h"
#include "cc/trees/mutator_host.h"
#include "ui/gfx/transform.h"
diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc
index ccb6a42ba3c..b283103cc48 100644
--- a/chromium/cc/animation/animation_host.cc
+++ b/chromium/cc/animation/animation_host.cc
@@ -81,8 +81,7 @@ AnimationHost::AnimationHost(ThreadInstance thread_instance)
thread_instance_(thread_instance),
supports_scroll_animations_(false),
needs_push_properties_(false),
- mutator_(nullptr),
- weak_factory_(this) {
+ mutator_(nullptr) {
if (thread_instance_ == ThreadInstance::IMPL) {
scroll_offset_animations_impl_ =
std::make_unique<ScrollOffsetAnimationsImpl>(this);
@@ -649,6 +648,18 @@ bool AnimationHost::HasTickingKeyframeModelForTesting(
: false;
}
+void AnimationHost::ImplOnlyAutoScrollAnimationCreate(
+ ElementId element_id,
+ const gfx::ScrollOffset& target_offset,
+ const gfx::ScrollOffset& current_offset,
+ float autoscroll_velocity,
+ base::TimeDelta animation_start_offset) {
+ DCHECK(scroll_offset_animations_impl_);
+ scroll_offset_animations_impl_->AutoScrollAnimationCreate(
+ element_id, target_offset, current_offset, autoscroll_velocity,
+ animation_start_offset);
+}
+
void AnimationHost::ImplOnlyScrollAnimationCreate(
ElementId element_id,
const gfx::ScrollOffset& target_offset,
@@ -690,7 +701,7 @@ bool AnimationHost::IsImplOnlyScrollAnimating() const {
}
void AnimationHost::AddToTicking(scoped_refptr<Animation> animation) {
- DCHECK(!base::ContainsValue(ticking_animations_, animation));
+ DCHECK(!base::Contains(ticking_animations_, animation));
ticking_animations_.push_back(animation);
}
diff --git a/chromium/cc/animation/animation_host.h b/chromium/cc/animation/animation_host.h
index 45fca14a5b7..2e3eb122c71 100644
--- a/chromium/cc/animation/animation_host.h
+++ b/chromium/cc/animation/animation_host.h
@@ -164,6 +164,13 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost,
bool IsElementAnimating(ElementId element_id) const override;
bool HasTickingKeyframeModelForTesting(ElementId element_id) const override;
+ void ImplOnlyAutoScrollAnimationCreate(
+ ElementId element_id,
+ const gfx::ScrollOffset& target_offset,
+ const gfx::ScrollOffset& current_offset,
+ float autoscroll_velocity,
+ base::TimeDelta animation_start_offset) override;
+
void ImplOnlyScrollAnimationCreate(
ElementId element_id,
const gfx::ScrollOffset& target_offset,
@@ -255,7 +262,7 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost,
bool current_frame_had_raf_ = false;
bool next_frame_has_pending_raf_ = false;
- base::WeakPtrFactory<AnimationHost> weak_factory_;
+ base::WeakPtrFactory<AnimationHost> weak_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/animation/element_animations.h b/chromium/cc/animation/element_animations.h
index e2a46551787..28de076c312 100644
--- a/chromium/cc/animation/element_animations.h
+++ b/chromium/cc/animation/element_animations.h
@@ -12,7 +12,7 @@
#include "base/observer_list.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/animation_target.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
#include "cc/trees/property_animation_state.h"
#include "cc/trees/target_property.h"
#include "ui/gfx/geometry/scroll_offset.h"
diff --git a/chromium/cc/animation/keyframe_effect.cc b/chromium/cc/animation/keyframe_effect.cc
index d1d55431893..221cf0b141e 100644
--- a/chromium/cc/animation/keyframe_effect.cc
+++ b/chromium/cc/animation/keyframe_effect.cc
@@ -276,7 +276,7 @@ void KeyframeEffect::RemoveKeyframeModel(int keyframe_model_id) {
bool keyframe_model_removed = false;
// Since we want to use the KeyframeModels that we're going to remove, we
- // need to use a stable_parition here instead of remove_if. Remove_if leaves
+ // need to use a stable_partition here instead of remove_if. remove_if leaves
// the removed items in an unspecified state.
auto keyframe_models_to_remove = std::stable_partition(
keyframe_models_.begin(), keyframe_models_.end(),
diff --git a/chromium/cc/animation/keyframe_effect.h b/chromium/cc/animation/keyframe_effect.h
index 3bcb0347439..e4b00292602 100644
--- a/chromium/cc/animation/keyframe_effect.h
+++ b/chromium/cc/animation/keyframe_effect.h
@@ -10,7 +10,7 @@
#include "cc/animation/animation_events.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/element_animations.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
#include "cc/trees/mutator_host_client.h"
#include "cc/trees/target_property.h"
#include "ui/gfx/geometry/box_f.h"
diff --git a/chromium/cc/animation/keyframe_model.cc b/chromium/cc/animation/keyframe_model.cc
index d4b89dda44b..50b3cef1ea2 100644
--- a/chromium/cc/animation/keyframe_model.cc
+++ b/chromium/cc/animation/keyframe_model.cc
@@ -12,6 +12,7 @@
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "cc/animation/animation_curve.h"
+#include "cc/trees/target_property.h"
namespace {
@@ -50,9 +51,11 @@ std::unique_ptr<KeyframeModel> KeyframeModel::Create(
std::unique_ptr<AnimationCurve> curve,
int keyframe_model_id,
int group_id,
- int target_property_id) {
+ int target_property_id,
+ const std::string& custom_property_name) {
return base::WrapUnique(new KeyframeModel(std::move(curve), keyframe_model_id,
- group_id, target_property_id));
+ group_id, target_property_id,
+ custom_property_name));
}
std::unique_ptr<KeyframeModel> KeyframeModel::CreateImplInstance(
@@ -61,7 +64,8 @@ std::unique_ptr<KeyframeModel> KeyframeModel::CreateImplInstance(
// creating multiple controlling instances.
DCHECK(!is_controlling_instance_);
std::unique_ptr<KeyframeModel> to_return(
- new KeyframeModel(curve_->Clone(), id_, group_, target_property_id_));
+ new KeyframeModel(curve_->Clone(), id_, group_, target_property_id_,
+ custom_property_name_));
to_return->element_id_ = element_id_;
to_return->run_state_ = initial_run_state;
to_return->iterations_ = iterations_;
@@ -81,7 +85,8 @@ std::unique_ptr<KeyframeModel> KeyframeModel::CreateImplInstance(
KeyframeModel::KeyframeModel(std::unique_ptr<AnimationCurve> curve,
int keyframe_model_id,
int group_id,
- int target_property_id)
+ int target_property_id,
+ const std::string& custom_property_name)
: curve_(std::move(curve)),
id_(keyframe_model_id),
group_(group_id),
@@ -97,7 +102,11 @@ KeyframeModel::KeyframeModel(std::unique_ptr<AnimationCurve> curve,
is_controlling_instance_(false),
is_impl_only_(false),
affects_active_elements_(true),
- affects_pending_elements_(true) {}
+ affects_pending_elements_(true),
+ custom_property_name_(custom_property_name) {
+ DCHECK(custom_property_name_.empty() ||
+ target_property_id_ == TargetProperty::CSS_CUSTOM_PROPERTY);
+}
KeyframeModel::~KeyframeModel() {
if (run_state_ == RUNNING || run_state_ == PAUSED)
diff --git a/chromium/cc/animation/keyframe_model.h b/chromium/cc/animation/keyframe_model.h
index 43a22d883ec..7c05245dc99 100644
--- a/chromium/cc/animation/keyframe_model.h
+++ b/chromium/cc/animation/keyframe_model.h
@@ -10,7 +10,7 @@
#include "base/optional.h"
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
namespace cc {
@@ -57,11 +57,15 @@ class CC_ANIMATION_EXPORT KeyframeModel {
enum class Phase { BEFORE, ACTIVE, AFTER };
+ // The |custom_property_name| has a default value of an empty string,
+ // indicating that the animated property is a native property. When it is an
+ // animated custom property, it should be the property name.
static std::unique_ptr<KeyframeModel> Create(
std::unique_ptr<AnimationCurve> curve,
int keyframe_model_id,
int group_id,
- int target_property_id);
+ int target_property_id,
+ const std::string& custom_property_name = "");
std::unique_ptr<KeyframeModel> CreateImplInstance(
RunState initial_run_state) const;
@@ -177,11 +181,16 @@ class CC_ANIMATION_EXPORT KeyframeModel {
KeyframeModel::Phase CalculatePhaseForTesting(
base::TimeDelta local_time) const;
+ const std::string& GetCustomPropertyNameForTesting() {
+ return custom_property_name_;
+ }
+
private:
KeyframeModel(std::unique_ptr<AnimationCurve> curve,
int keyframe_model_id,
int group_id,
- int target_property_id);
+ int target_property_id,
+ const std::string& custom_property_name);
// Return local time for this keyframe model given the absolute monotonic
// time.
@@ -281,6 +290,10 @@ class CC_ANIMATION_EXPORT KeyframeModel {
// longer affect any elements, and are deleted.
bool affects_active_elements_;
bool affects_pending_elements_;
+
+ // Name of the animated custom property. Empty if it is an animated native
+ // property.
+ std::string custom_property_name_;
};
} // namespace cc
diff --git a/chromium/cc/animation/keyframe_model_unittest.cc b/chromium/cc/animation/keyframe_model_unittest.cc
index 5c853eb1246..b5648c0c370 100644
--- a/chromium/cc/animation/keyframe_model_unittest.cc
+++ b/chromium/cc/animation/keyframe_model_unittest.cc
@@ -1384,5 +1384,19 @@ TEST(KeyframeModelTest, ToString) {
keyframe_model->ToString());
}
+TEST(KeyframeModelTest, CustomPropertyKeyframe) {
+ std::unique_ptr<KeyframeModel> keyframe_model =
+ KeyframeModel::Create(std::make_unique<FakeFloatAnimationCurve>(1), 1, 1,
+ TargetProperty::CSS_CUSTOM_PROPERTY, "foo");
+ EXPECT_EQ(keyframe_model->GetCustomPropertyNameForTesting(), "foo");
+}
+
+TEST(KeyframeModelTest, NonCustomPropertyKeyframe) {
+ std::unique_ptr<KeyframeModel> keyframe_model =
+ KeyframeModel::Create(std::make_unique<FakeFloatAnimationCurve>(1), 1, 1,
+ TargetProperty::TRANSFORM);
+ EXPECT_EQ(keyframe_model->GetCustomPropertyNameForTesting(), "");
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/animation/keyframed_animation_curve.cc b/chromium/cc/animation/keyframed_animation_curve.cc
index ed44328d053..67147cb86a4 100644
--- a/chromium/cc/animation/keyframed_animation_curve.cc
+++ b/chromium/cc/animation/keyframed_animation_curve.cc
@@ -541,8 +541,8 @@ gfx::SizeF KeyframedSizeAnimationCurve::GetValue(base::TimeDelta t) const {
double progress =
TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
- return gfx::Tween::SizeValueBetween(progress, keyframes_[i]->Value(),
- keyframes_[i + 1]->Value());
+ return gfx::Tween::SizeFValueBetween(progress, keyframes_[i]->Value(),
+ keyframes_[i + 1]->Value());
}
} // namespace cc
diff --git a/chromium/cc/animation/keyframed_animation_curve.h b/chromium/cc/animation/keyframed_animation_curve.h
index 27e87ba3648..c843fc7f782 100644
--- a/chromium/cc/animation/keyframed_animation_curve.h
+++ b/chromium/cc/animation/keyframed_animation_curve.h
@@ -164,12 +164,15 @@ class CC_ANIMATION_EXPORT KeyframedColorAnimationCurve
// BackgrounColorAnimationCurve implementation
SkColor GetValue(base::TimeDelta t) const override;
+ using Keyframes = std::vector<std::unique_ptr<ColorKeyframe>>;
+ const Keyframes& keyframes_for_testing() const { return keyframes_; }
+
private:
KeyframedColorAnimationCurve();
// Always sorted in order of increasing time. No two keyframes have the
// same time.
- std::vector<std::unique_ptr<ColorKeyframe>> keyframes_;
+ Keyframes keyframes_;
std::unique_ptr<TimingFunction> timing_function_;
double scaled_duration_;
};
diff --git a/chromium/cc/animation/keyframed_animation_curve_unittest.cc b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
index 4b678bdfac6..60fa0054a2c 100644
--- a/chromium/cc/animation/keyframed_animation_curve_unittest.cc
+++ b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
@@ -519,6 +519,19 @@ TEST(KeyframedAnimationCurveTest, UnsortedKeyframes) {
EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
+// Tests that a linear timing function works as expected.
+TEST(KeyframedAnimationCurveTest, LinearTimingFunction) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f,
+ LinearTimingFunction::Create()));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
+
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(0.75f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+}
+
// Tests that a cubic bezier timing function works as expected.
TEST(KeyframedAnimationCurveTest, CubicBezierTimingFunction) {
std::unique_ptr<KeyframedFloatAnimationCurve> curve(
@@ -1004,7 +1017,7 @@ TEST(KeyframedAnimationCurveTest, OneSizeKeyFrame) {
TEST(KeyframedAnimationCurveTest, TwoSizeKeyFrame) {
gfx::SizeF size_a = gfx::SizeF(100, 100);
gfx::SizeF size_b = gfx::SizeF(100, 0);
- gfx::SizeF size_midpoint = gfx::Tween::SizeValueBetween(0.5, size_a, size_b);
+ gfx::SizeF size_midpoint = gfx::Tween::SizeFValueBetween(0.5, size_a, size_b);
std::unique_ptr<KeyframedSizeAnimationCurve> curve(
KeyframedSizeAnimationCurve::Create());
curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size_a, nullptr));
@@ -1024,8 +1037,10 @@ TEST(KeyframedAnimationCurveTest, ThreeSizeKeyFrame) {
gfx::SizeF size_a = gfx::SizeF(100, 100);
gfx::SizeF size_b = gfx::SizeF(100, 0);
gfx::SizeF size_c = gfx::SizeF(200, 0);
- gfx::SizeF size_midpoint1 = gfx::Tween::SizeValueBetween(0.5, size_a, size_b);
- gfx::SizeF size_midpoint2 = gfx::Tween::SizeValueBetween(0.5, size_b, size_c);
+ gfx::SizeF size_midpoint1 =
+ gfx::Tween::SizeFValueBetween(0.5, size_a, size_b);
+ gfx::SizeF size_midpoint2 =
+ gfx::Tween::SizeFValueBetween(0.5, size_b, size_c);
std::unique_ptr<KeyframedSizeAnimationCurve> curve(
KeyframedSizeAnimationCurve::Create());
curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size_a, nullptr));
diff --git a/chromium/cc/animation/scroll_offset_animation_curve.cc b/chromium/cc/animation/scroll_offset_animation_curve.cc
index 4dedca4a205..0bc523ff275 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve.cc
+++ b/chromium/cc/animation/scroll_offset_animation_curve.cc
@@ -82,7 +82,8 @@ ScrollOffsetAnimationCurve::~ScrollOffsetAnimationCurve() = default;
base::TimeDelta ScrollOffsetAnimationCurve::SegmentDuration(
const gfx::Vector2dF& delta,
DurationBehavior behavior,
- base::TimeDelta delayed_by) {
+ base::TimeDelta delayed_by,
+ float velocity) {
double duration = kConstantDuration;
if (!animation_duration_for_testing_) {
switch (behavior) {
@@ -101,6 +102,10 @@ base::TimeDelta ScrollOffsetAnimationCurve::SegmentDuration(
kInverseDeltaMinDuration),
kInverseDeltaMaxDuration);
break;
+ case DurationBehavior::CONSTANT_VELOCITY:
+ duration =
+ std::abs(MaximumDimension(delta) / velocity * kDurationDivisor);
+ break;
default:
NOTREACHED();
}
@@ -119,11 +124,13 @@ base::TimeDelta ScrollOffsetAnimationCurve::SegmentDuration(
void ScrollOffsetAnimationCurve::SetInitialValue(
const gfx::ScrollOffset& initial_value,
- base::TimeDelta delayed_by) {
+ base::TimeDelta delayed_by,
+ float velocity) {
initial_value_ = initial_value;
has_set_initial_value_ = true;
- total_animation_duration_ = SegmentDuration(
- target_value_.DeltaFrom(initial_value_), duration_behavior_, delayed_by);
+ total_animation_duration_ =
+ SegmentDuration(target_value_.DeltaFrom(initial_value_),
+ duration_behavior_, delayed_by, velocity);
}
bool ScrollOffsetAnimationCurve::HasSetInitialValue() const {
@@ -233,11 +240,11 @@ void ScrollOffsetAnimationCurve::UpdateTarget(
gfx::Vector2dF old_delta = target_value_.DeltaFrom(initial_value_);
gfx::Vector2dF new_delta = new_target.DeltaFrom(current_position);
- // The last segement was of zero duration.
+ // The last segment was of zero duration.
if ((total_animation_duration_ - last_retarget_).is_zero()) {
DCHECK_EQ(t, last_retarget_);
- total_animation_duration_ =
- SegmentDuration(new_delta, duration_behavior_, delayed_by);
+ total_animation_duration_ = SegmentDuration(new_delta, duration_behavior_,
+ delayed_by, /*velocity*/ 0);
target_value_ = new_target;
return;
}
@@ -250,7 +257,8 @@ void ScrollOffsetAnimationCurve::UpdateTarget(
// segment duration. This minimizes the "rubber-band" bouncing effect when
// old_normalized_velocity is large and new_delta is small.
base::TimeDelta new_duration =
- std::min(SegmentDuration(new_delta, duration_behavior_, delayed_by),
+ std::min(SegmentDuration(new_delta, duration_behavior_, delayed_by,
+ /*velocity*/ 0),
VelocityBasedDurationBound(old_delta, old_normalized_velocity,
old_duration, new_delta));
diff --git a/chromium/cc/animation/scroll_offset_animation_curve.h b/chromium/cc/animation/scroll_offset_animation_curve.h
index fca9af6942b..42b774b9c47 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve.h
+++ b/chromium/cc/animation/scroll_offset_animation_curve.h
@@ -35,7 +35,9 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
// Duration inversely proportional to scroll delta within certain bounds.
// Used for mouse wheels, makes fast wheel flings feel "snappy" while
// preserving smoothness of slow wheel movements.
- INVERSE_DELTA
+ INVERSE_DELTA,
+ // Constant velocity; used for autoscrolls.
+ CONSTANT_VELOCITY,
};
static std::unique_ptr<ScrollOffsetAnimationCurve> Create(
const gfx::ScrollOffset& target_value,
@@ -44,7 +46,8 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
static base::TimeDelta SegmentDuration(const gfx::Vector2dF& delta,
DurationBehavior behavior,
- base::TimeDelta delayed_by);
+ base::TimeDelta delayed_by,
+ float velocity);
ScrollOffsetAnimationCurve(const ScrollOffsetAnimationCurve&) = delete;
~ScrollOffsetAnimationCurve() override;
@@ -52,8 +55,10 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
ScrollOffsetAnimationCurve& operator=(const ScrollOffsetAnimationCurve&) =
delete;
+ // Sets the initial offset and velocity (in pixels per second).
void SetInitialValue(const gfx::ScrollOffset& initial_value,
- base::TimeDelta delayed_by = base::TimeDelta());
+ base::TimeDelta delayed_by = base::TimeDelta(),
+ float velocity = 0);
bool HasSetInitialValue() const;
gfx::ScrollOffset GetValue(base::TimeDelta t) const;
gfx::ScrollOffset target_value() const { return target_value_; }
diff --git a/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc
index cd308a709b8..61bc09be18e 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc
+++ b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc
@@ -205,6 +205,33 @@ TEST(ScrollOffsetAnimationCurveTest, InverseDeltaDuration) {
EXPECT_EQ(largeDeltaDuration, curve->Duration().InSecondsF());
}
+TEST(ScrollOffsetAnimationCurveTest, ConstantVelocityDuration) {
+ // Testing autoscroll downwards for a scroller of length 1000px.
+ gfx::ScrollOffset current_offset(0.f, 0.f);
+ gfx::ScrollOffset target_offset(0.f, 1000.f);
+ std::unique_ptr<ScrollOffsetAnimationCurve> curve(
+ ScrollOffsetAnimationCurve::Create(
+ target_offset, LinearTimingFunction::Create(),
+ ScrollOffsetAnimationCurve::DurationBehavior::CONSTANT_VELOCITY));
+
+ const float autoscroll_velocity = 800.f; // pixels per second.
+ curve->SetInitialValue(current_offset, base::TimeDelta(),
+ autoscroll_velocity);
+ EXPECT_FLOAT_EQ(1.25f, curve->Duration().InSecondsF());
+
+ // Test scrolling down from half way.
+ current_offset = gfx::ScrollOffset(0.f, 500.f);
+ curve->SetInitialValue(current_offset, base::TimeDelta(),
+ autoscroll_velocity);
+ EXPECT_FLOAT_EQ(0.625f, curve->Duration().InSecondsF());
+
+ // Test scrolling down when max_offset is reached.
+ current_offset = gfx::ScrollOffset(0.f, 1000.f);
+ curve->SetInitialValue(current_offset, base::TimeDelta(),
+ autoscroll_velocity);
+ EXPECT_FLOAT_EQ(0.f, curve->Duration().InSecondsF());
+}
+
TEST(ScrollOffsetAnimationCurveTest, CurveWithDelay) {
std::unique_ptr<ScrollOffsetAnimationCurve> curve(
ScrollOffsetAnimationCurve::Create(
@@ -244,7 +271,7 @@ TEST(ScrollOffsetAnimationCurveTest, CurveWithLargeDelay) {
ScrollOffsetAnimationCurve::SegmentDuration(
gfx::Vector2dF(0.f, 200.f),
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA,
- base::TimeDelta::FromSecondsD(0.01))
+ base::TimeDelta::FromSecondsD(0.01), /*velocity*/ 0)
.InSecondsF();
EXPECT_EQ(duration, curve->Duration().InSecondsF());
@@ -255,7 +282,7 @@ TEST(ScrollOffsetAnimationCurveTest, CurveWithLargeDelay) {
duration = ScrollOffsetAnimationCurve::SegmentDuration(
gfx::Vector2dF(0.f, 500.f),
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA,
- base::TimeDelta::FromSecondsD(0.01))
+ base::TimeDelta::FromSecondsD(0.01), /*velocity*/ 0)
.InSecondsF();
EXPECT_EQ(duration, curve->Duration().InSecondsF());
@@ -288,7 +315,7 @@ TEST(ScrollOffsetAnimationCurveTest, UpdateTargetZeroLastSegmentDuration) {
ScrollOffsetAnimationCurve::SegmentDuration(
gfx::Vector2dF(new_delta.x(), new_delta.y()),
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA,
- base::TimeDelta())
+ base::TimeDelta(), /*velocity*/ 0)
.InSecondsF() +
0.05;
curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.05),
@@ -309,7 +336,7 @@ TEST(ScrollOffsetAnimationCurveTest, UpdateTargetZeroLastSegmentDuration) {
ScrollOffsetAnimationCurve::SegmentDuration(
gfx::Vector2dF(new_delta.x(), new_delta.y()),
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA,
- base::TimeDelta::FromSecondsD(0.15))
+ base::TimeDelta::FromSecondsD(0.15), /*velocity*/ 0)
.InSecondsF();
curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.1),
gfx::ScrollOffset(0.f, 500.f));
diff --git a/chromium/cc/animation/scroll_offset_animations_impl.cc b/chromium/cc/animation/scroll_offset_animations_impl.cc
index 896e17440be..5c7ff936114 100644
--- a/chromium/cc/animation/scroll_offset_animations_impl.cc
+++ b/chromium/cc/animation/scroll_offset_animations_impl.cc
@@ -34,6 +34,22 @@ ScrollOffsetAnimationsImpl::~ScrollOffsetAnimationsImpl() {
animation_host_->RemoveAnimationTimeline(scroll_offset_timeline_.get());
}
+void ScrollOffsetAnimationsImpl::AutoScrollAnimationCreate(
+ ElementId element_id,
+ const gfx::ScrollOffset& target_offset,
+ const gfx::ScrollOffset& current_offset,
+ float autoscroll_velocity,
+ base::TimeDelta animation_start_offset) {
+ std::unique_ptr<ScrollOffsetAnimationCurve> curve =
+ ScrollOffsetAnimationCurve::Create(
+ target_offset, LinearTimingFunction::Create(),
+ ScrollOffsetAnimationCurve::DurationBehavior::CONSTANT_VELOCITY);
+ curve->SetInitialValue(current_offset, base::TimeDelta(),
+ autoscroll_velocity);
+ ScrollAnimationCreateInternal(element_id, std::move(curve),
+ animation_start_offset);
+}
+
void ScrollOffsetAnimationsImpl::ScrollAnimationCreate(
ElementId element_id,
const gfx::ScrollOffset& target_offset,
@@ -42,10 +58,19 @@ void ScrollOffsetAnimationsImpl::ScrollAnimationCreate(
base::TimeDelta animation_start_offset) {
std::unique_ptr<ScrollOffsetAnimationCurve> curve =
ScrollOffsetAnimationCurve::Create(
- target_offset, CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE_IN_OUT),
+ target_offset,
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE_IN_OUT),
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA);
curve->SetInitialValue(current_offset, delayed_by);
+ ScrollAnimationCreateInternal(element_id, std::move(curve),
+ animation_start_offset);
+}
+
+void ScrollOffsetAnimationsImpl::ScrollAnimationCreateInternal(
+ ElementId element_id,
+ std::unique_ptr<AnimationCurve> curve,
+ base::TimeDelta animation_start_offset) {
TRACE_EVENT_INSTANT1("cc", "ScrollAnimationCreate", TRACE_EVENT_SCOPE_THREAD,
"Duration", curve->Duration().InMillisecondsF());
diff --git a/chromium/cc/animation/scroll_offset_animations_impl.h b/chromium/cc/animation/scroll_offset_animations_impl.h
index 39d72f18cd6..4371deed459 100644
--- a/chromium/cc/animation/scroll_offset_animations_impl.h
+++ b/chromium/cc/animation/scroll_offset_animations_impl.h
@@ -32,6 +32,12 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationsImpl
ScrollOffsetAnimationsImpl& operator=(const ScrollOffsetAnimationsImpl&) =
delete;
+ void AutoScrollAnimationCreate(ElementId element_id,
+ const gfx::ScrollOffset& target_offset,
+ const gfx::ScrollOffset& current_offset,
+ float autoscroll_velocity,
+ base::TimeDelta animation_start_offset);
+
// |delayed_by| shrinks the duration of the
// animation. |animation_start_offset| causes us to start the animation
// partway through.
@@ -73,6 +79,10 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationsImpl
bool IsAnimating() const;
private:
+ void ScrollAnimationCreateInternal(ElementId element_id,
+ std::unique_ptr<AnimationCurve> curve,
+ base::TimeDelta animation_start_offset);
+
void ReattachScrollOffsetAnimationIfNeeded(ElementId element_id);
AnimationHost* animation_host_;
diff --git a/chromium/cc/animation/scroll_timeline.h b/chromium/cc/animation/scroll_timeline.h
index 152c1a642db..66b39d562fc 100644
--- a/chromium/cc/animation/scroll_timeline.h
+++ b/chromium/cc/animation/scroll_timeline.h
@@ -9,7 +9,7 @@
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/keyframe_model.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
namespace cc {
diff --git a/chromium/cc/animation/single_keyframe_effect_animation.h b/chromium/cc/animation/single_keyframe_effect_animation.h
index 474250c8a9a..a79566ae28e 100644
--- a/chromium/cc/animation/single_keyframe_effect_animation.h
+++ b/chromium/cc/animation/single_keyframe_effect_animation.h
@@ -15,7 +15,7 @@
#include "cc/animation/animation_export.h"
#include "cc/animation/element_animations.h"
#include "cc/animation/keyframe_model.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
namespace cc {
diff --git a/chromium/cc/animation/timing_function.cc b/chromium/cc/animation/timing_function.cc
index 1c80aeeb28d..d3a66810330 100644
--- a/chromium/cc/animation/timing_function.cc
+++ b/chromium/cc/animation/timing_function.cc
@@ -105,23 +105,77 @@ double StepsTimingFunction::GetPreciseValue(double t,
steps * t - std::floor(steps * t) == 0) {
current_step -= 1;
}
+ // Jumps may differ from steps based on the number of end-point
+ // discontinuities, which may be 0, 1 or 2.
+ int jumps = NumberOfJumps();
if (t >= 0 && current_step < 0)
current_step = 0;
- if (t <= 1 && current_step > steps)
- current_step = steps;
- return current_step / steps;
+ if (t <= 1 && current_step > jumps)
+ current_step = jumps;
+ return current_step / jumps;
+}
+
+int StepsTimingFunction::NumberOfJumps() const {
+ switch (step_position_) {
+ case StepPosition::END:
+ case StepPosition::START:
+ case StepPosition::JUMP_END:
+ case StepPosition::JUMP_START:
+ return steps_;
+
+ case StepPosition::JUMP_BOTH:
+ return steps_ + 1;
+
+ case StepPosition::JUMP_NONE:
+ DCHECK_GT(steps_, 1);
+ return steps_ - 1;
+
+ default:
+ NOTREACHED();
+ return steps_;
+ }
}
float StepsTimingFunction::GetStepsStartOffset() const {
switch (step_position_) {
+ case StepPosition::JUMP_BOTH:
+ case StepPosition::JUMP_START:
case StepPosition::START:
return 1;
+
+ case StepPosition::JUMP_END:
+ case StepPosition::JUMP_NONE:
case StepPosition::END:
return 0;
+
default:
NOTREACHED();
return 1;
}
}
+std::unique_ptr<LinearTimingFunction> LinearTimingFunction::Create() {
+ return base::WrapUnique(new LinearTimingFunction());
+}
+
+LinearTimingFunction::LinearTimingFunction() = default;
+
+LinearTimingFunction::~LinearTimingFunction() = default;
+
+TimingFunction::Type LinearTimingFunction::GetType() const {
+ return Type::LINEAR;
+}
+
+std::unique_ptr<TimingFunction> LinearTimingFunction::Clone() const {
+ return base::WrapUnique(new LinearTimingFunction(*this));
+}
+
+double LinearTimingFunction::Velocity(double x) const {
+ return 0;
+}
+
+double LinearTimingFunction::GetValue(double t) const {
+ return t;
+}
+
} // namespace cc
diff --git a/chromium/cc/animation/timing_function.h b/chromium/cc/animation/timing_function.h
index 4212bb28864..4422a4a6f7d 100644
--- a/chromium/cc/animation/timing_function.h
+++ b/chromium/cc/animation/timing_function.h
@@ -73,7 +73,18 @@ class CC_ANIMATION_EXPORT StepsTimingFunction : public TimingFunction {
public:
// step-timing-function values
// https://drafts.csswg.org/css-easing-1/#typedef-step-timing-function
- enum class StepPosition { START, END };
+ enum class StepPosition {
+ START, // Discontinuity at progress = 0.
+ // Alias for jump-start. Maintaining a separate enumerated value
+ // for serialization.
+ END, // Discontinuity at progress = 1.
+ // Alias for jump-end. Maintaining a separate enumerated value
+ // for serialization.
+ JUMP_BOTH, // Discontinuities at progress = 0 and 1.
+ JUMP_END, // Discontinuity at progress = 1.
+ JUMP_NONE, // Continuous at progress = 0 and 1.
+ JUMP_START // Discontinuity at progress = 0.
+ };
static std::unique_ptr<StepsTimingFunction> Create(
int steps,
@@ -95,12 +106,35 @@ class CC_ANIMATION_EXPORT StepsTimingFunction : public TimingFunction {
private:
StepsTimingFunction(int steps, StepPosition step_position);
+ // The number of jumps is the number of discontinuities in the timing
+ // function. There is a subtle distinction between the number of steps and
+ // jumps. The number of steps is the number of intervals in the timing
+ // function. The number of jumps differs from the number of steps when either
+ // both or neither end point has a discontinuity.
+ // https://drafts.csswg.org/css-easing-1/#step-easing-functions
+ int NumberOfJumps() const;
+
float GetStepsStartOffset() const;
int steps_;
StepPosition step_position_;
};
+class CC_ANIMATION_EXPORT LinearTimingFunction : public TimingFunction {
+ public:
+ static std::unique_ptr<LinearTimingFunction> Create();
+ ~LinearTimingFunction() override;
+
+ // TimingFunction implementation.
+ Type GetType() const override;
+ double GetValue(double t) const override;
+ std::unique_ptr<TimingFunction> Clone() const override;
+ double Velocity(double time) const override;
+
+ private:
+ LinearTimingFunction();
+};
+
} // namespace cc
#endif // CC_ANIMATION_TIMING_FUNCTION_H_
diff --git a/chromium/cc/base/delayed_unique_notifier.cc b/chromium/cc/base/delayed_unique_notifier.cc
index 741bc83c71f..3148c0f788f 100644
--- a/chromium/cc/base/delayed_unique_notifier.cc
+++ b/chromium/cc/base/delayed_unique_notifier.cc
@@ -18,8 +18,7 @@ DelayedUniqueNotifier::DelayedUniqueNotifier(
: task_runner_(task_runner),
closure_(std::move(closure)),
delay_(delay),
- notification_pending_(false),
- weak_ptr_factory_(this) {}
+ notification_pending_(false) {}
DelayedUniqueNotifier::~DelayedUniqueNotifier() = default;
diff --git a/chromium/cc/base/delayed_unique_notifier.h b/chromium/cc/base/delayed_unique_notifier.h
index 16669879d00..b70de390844 100644
--- a/chromium/cc/base/delayed_unique_notifier.h
+++ b/chromium/cc/base/delayed_unique_notifier.h
@@ -67,7 +67,7 @@ class CC_BASE_EXPORT DelayedUniqueNotifier {
base::TimeTicks next_notification_time_;
bool notification_pending_;
- base::WeakPtrFactory<DelayedUniqueNotifier> weak_ptr_factory_;
+ base::WeakPtrFactory<DelayedUniqueNotifier> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/base/devtools_instrumentation.cc b/chromium/cc/base/devtools_instrumentation.cc
index fab22da704c..d348592276c 100644
--- a/chromium/cc/base/devtools_instrumentation.cc
+++ b/chromium/cc/base/devtools_instrumentation.cc
@@ -43,6 +43,9 @@ ScopedImageDecodeTask::ScopedImageDecodeTask(const void* image_ptr,
ScopedImageDecodeTask::~ScopedImageDecodeTask() {
TRACE_EVENT_END0(internal::CategoryName::kTimeline,
internal::kImageDecodeTask);
+ if (suppress_metrics_)
+ return;
+
base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
switch (task_type_) {
case kInRaster:
diff --git a/chromium/cc/base/devtools_instrumentation.h b/chromium/cc/base/devtools_instrumentation.h
index 56077e041e4..052bff459a5 100644
--- a/chromium/cc/base/devtools_instrumentation.h
+++ b/chromium/cc/base/devtools_instrumentation.h
@@ -76,10 +76,15 @@ class CC_BASE_EXPORT ScopedImageDecodeTask {
ScopedImageDecodeTask& operator=(const ScopedImageDecodeTask&) = delete;
+ // Prevents logging duration metrics. Used in cases where a task performed
+ // uninteresting work or was terminated early.
+ void SuppressMetrics() { suppress_metrics_ = true; }
+
private:
const DecodeType decode_type_;
const TaskType task_type_;
const base::TimeTicks start_time_;
+ bool suppress_metrics_ = false;
};
class CC_BASE_EXPORT ScopedLayerTreeTask {
diff --git a/chromium/cc/base/rolling_time_delta_history.cc b/chromium/cc/base/rolling_time_delta_history.cc
index dde20a7bbe4..6973e42414a 100644
--- a/chromium/cc/base/rolling_time_delta_history.cc
+++ b/chromium/cc/base/rolling_time_delta_history.cc
@@ -29,6 +29,13 @@ void RollingTimeDeltaHistory::InsertSample(base::TimeDelta time) {
percentile_cache_.clear();
}
+void RollingTimeDeltaHistory::RemoveOldestSample() {
+ if (sample_set_.size() > 0) {
+ sample_set_.erase(chronological_sample_deque_.front());
+ chronological_sample_deque_.pop_front();
+ }
+}
+
void RollingTimeDeltaHistory::Clear() {
chronological_sample_deque_.clear();
sample_set_.clear();
diff --git a/chromium/cc/base/rolling_time_delta_history.h b/chromium/cc/base/rolling_time_delta_history.h
index 75832323278..81aa8d263bd 100644
--- a/chromium/cc/base/rolling_time_delta_history.h
+++ b/chromium/cc/base/rolling_time_delta_history.h
@@ -28,6 +28,7 @@ class CC_BASE_EXPORT RollingTimeDeltaHistory {
RollingTimeDeltaHistory& operator=(const RollingTimeDeltaHistory&) = delete;
void InsertSample(base::TimeDelta time);
+ void RemoveOldestSample();
size_t sample_count() const { return sample_set_.size(); }
void Clear();
diff --git a/chromium/cc/base/unique_notifier.cc b/chromium/cc/base/unique_notifier.cc
index 52e7a498de3..5a3ada85187 100644
--- a/chromium/cc/base/unique_notifier.cc
+++ b/chromium/cc/base/unique_notifier.cc
@@ -15,8 +15,7 @@ UniqueNotifier::UniqueNotifier(base::SequencedTaskRunner* task_runner,
base::RepeatingClosure closure)
: task_runner_(task_runner),
closure_(std::move(closure)),
- notification_pending_(false),
- weak_ptr_factory_(this) {}
+ notification_pending_(false) {}
UniqueNotifier::~UniqueNotifier() = default;
diff --git a/chromium/cc/base/unique_notifier.h b/chromium/cc/base/unique_notifier.h
index ad2172b4213..2366b611b68 100644
--- a/chromium/cc/base/unique_notifier.h
+++ b/chromium/cc/base/unique_notifier.h
@@ -48,7 +48,7 @@ class CC_BASE_EXPORT UniqueNotifier {
base::Lock lock_;
bool notification_pending_;
- base::WeakPtrFactory<UniqueNotifier> weak_ptr_factory_;
+ base::WeakPtrFactory<UniqueNotifier> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/benchmarks/micro_benchmark_impl.cc b/chromium/cc/benchmarks/micro_benchmark_impl.cc
index a37ad345277..2dacb125406 100644
--- a/chromium/cc/benchmarks/micro_benchmark_impl.cc
+++ b/chromium/cc/benchmarks/micro_benchmark_impl.cc
@@ -31,7 +31,7 @@ void MicroBenchmarkImpl::DidCompleteCommit(LayerTreeHostImpl* host) {}
void MicroBenchmarkImpl::NotifyDone(std::unique_ptr<base::Value> result) {
origin_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback_), base::Passed(&result)));
+ FROM_HERE, base::BindOnce(std::move(callback_), std::move(result)));
is_done_ = true;
}
diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc b/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc
index 844f66aef1d..b3ca388b131 100644
--- a/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc
+++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc
@@ -74,8 +74,7 @@ RasterizeAndRecordBenchmark::RasterizeAndRecordBenchmark(
record_repeat_count_(kDefaultRecordRepeatCount),
settings_(std::move(value)),
main_thread_benchmark_done_(false),
- layer_tree_host_(nullptr),
- weak_ptr_factory_(this) {
+ layer_tree_host_(nullptr) {
base::DictionaryValue* settings = nullptr;
settings_->GetAsDictionary(&settings);
if (!settings)
diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark.h b/chromium/cc/benchmarks/rasterize_and_record_benchmark.h
index efb6266b9fb..8ca7c588a1f 100644
--- a/chromium/cc/benchmarks/rasterize_and_record_benchmark.h
+++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark.h
@@ -62,7 +62,7 @@ class RasterizeAndRecordBenchmark : public MicroBenchmark {
LayerTreeHost* layer_tree_host_;
- base::WeakPtrFactory<RasterizeAndRecordBenchmark> weak_ptr_factory_;
+ base::WeakPtrFactory<RasterizeAndRecordBenchmark> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
index a1f8b53f202..93b5d5dfc4e 100644
--- a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
+++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
@@ -95,7 +95,7 @@ class FixedInvalidationPictureLayerTilingClient
return base_client_->CreateTile(info);
}
- gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override {
+ gfx::Size CalculateTileSize(const gfx::Size& content_bounds) override {
return base_client_->CalculateTileSize(content_bounds);
}
@@ -116,6 +116,10 @@ class FixedInvalidationPictureLayerTilingClient
return base_client_->RequiresHighResToDraw();
}
+ const PaintWorkletRecordMap& GetPaintWorkletRecords() const override {
+ return base_client_->GetPaintWorkletRecords();
+ }
+
private:
PictureLayerTilingClient* base_client_;
Region invalidation_;
diff --git a/chromium/cc/benchmarks/unittest_only_benchmark.cc b/chromium/cc/benchmarks/unittest_only_benchmark.cc
index 4e32942140a..efb46c63b90 100644
--- a/chromium/cc/benchmarks/unittest_only_benchmark.cc
+++ b/chromium/cc/benchmarks/unittest_only_benchmark.cc
@@ -14,9 +14,7 @@ namespace cc {
UnittestOnlyBenchmark::UnittestOnlyBenchmark(std::unique_ptr<base::Value> value,
DoneCallback callback)
- : MicroBenchmark(std::move(callback)),
- create_impl_benchmark_(false),
- weak_ptr_factory_(this) {
+ : MicroBenchmark(std::move(callback)), create_impl_benchmark_(false) {
if (!value)
return;
diff --git a/chromium/cc/benchmarks/unittest_only_benchmark.h b/chromium/cc/benchmarks/unittest_only_benchmark.h
index fa0f63d6f25..7ba9a9e1ded 100644
--- a/chromium/cc/benchmarks/unittest_only_benchmark.h
+++ b/chromium/cc/benchmarks/unittest_only_benchmark.h
@@ -28,7 +28,7 @@ class CC_EXPORT UnittestOnlyBenchmark : public MicroBenchmark {
void RecordImplResults(std::unique_ptr<base::Value> results);
bool create_impl_benchmark_;
- base::WeakPtrFactory<UnittestOnlyBenchmark> weak_ptr_factory_;
+ base::WeakPtrFactory<UnittestOnlyBenchmark> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/debug/debug_colors.cc b/chromium/cc/debug/debug_colors.cc
index d8fc52a0da8..c16f4fbec8b 100644
--- a/chromium/cc/debug/debug_colors.cc
+++ b/chromium/cc/debug/debug_colors.cc
@@ -194,6 +194,25 @@ SkColor DebugColors::PaintRectFillColor(int step) {
return FadedGreen(60, step);
}
+static SkColor FadedBlue(int initial_value, int step) {
+ DCHECK_GE(step, 0);
+ DCHECK_LE(step, DebugColors::kFadeSteps);
+ int value = step * initial_value / DebugColors::kFadeSteps;
+ return SkColorSetARGB(value, 0, 0, 255);
+}
+/// Layout Shift rects in blue.
+SkColor DebugColors::LayoutShiftRectBorderColor() {
+ return SkColorSetARGB(0, 0, 0, 255);
+}
+int DebugColors::LayoutShiftRectBorderWidth() {
+ // We don't want any border showing for the layout shift debug rects so we set
+ // the border width to be equal to 0.
+ return 0;
+}
+SkColor DebugColors::LayoutShiftRectFillColor(int step) {
+ return FadedBlue(60, step);
+}
+
// Property-changed rects in blue.
SkColor DebugColors::PropertyChangedRectBorderColor() {
return SkColorSetARGB(255, 0, 0, 255);
diff --git a/chromium/cc/debug/debug_colors.h b/chromium/cc/debug/debug_colors.h
index 69a73b1d47d..8e13fcbb8d4 100644
--- a/chromium/cc/debug/debug_colors.h
+++ b/chromium/cc/debug/debug_colors.h
@@ -72,6 +72,10 @@ class CC_DEBUG_EXPORT DebugColors {
static int PaintRectBorderWidth();
static SkColor PaintRectFillColor(int step);
+ static SkColor LayoutShiftRectBorderColor();
+ static int LayoutShiftRectBorderWidth();
+ static SkColor LayoutShiftRectFillColor(int step);
+
static SkColor PropertyChangedRectBorderColor();
static int PropertyChangedRectBorderWidth();
static SkColor PropertyChangedRectFillColor();
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index 0c41e257c7d..80e9bf42b20 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -15,8 +15,9 @@
#include "cc/input/scroll_state.h"
#include "cc/input/scrollbar.h"
#include "cc/input/touch_action.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
#include "cc/trees/swap_promise_monitor.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "ui/events/types/scroll_types.h"
namespace gfx {
@@ -94,7 +95,8 @@ class CC_EXPORT InputHandlerClient {
float page_scale_factor,
float min_page_scale_factor,
float max_page_scale_factor) = 0;
- virtual void DeliverInputForBeginFrame() = 0;
+ virtual void DeliverInputForBeginFrame(const viz::BeginFrameArgs& args) = 0;
+ virtual void DeliverInputForHighLatencyMode() = 0;
protected:
InputHandlerClient() = default;
@@ -223,8 +225,8 @@ class CC_EXPORT InputHandler {
virtual bool IsCurrentlyScrollingViewport() const = 0;
// Whether the layer under |viewport_point| is the currently scrolling layer.
- virtual bool IsCurrentlyScrollingLayerAt(const gfx::Point& viewport_point,
- ScrollInputType type) const = 0;
+ virtual bool IsCurrentlyScrollingLayerAt(
+ const gfx::Point& viewport_point) const = 0;
virtual EventListenerProperties GetEventListenerProperties(
EventListenerClass event_class) const = 0;
diff --git a/chromium/cc/input/scroll_state.h b/chromium/cc/input/scroll_state.h
index 11114c0293b..658d356dc91 100644
--- a/chromium/cc/input/scroll_state.h
+++ b/chromium/cc/input/scroll_state.h
@@ -99,6 +99,8 @@ class CC_EXPORT ScrollState {
bool is_scroll_chain_cut() const { return data_.is_scroll_chain_cut; }
+ double delta_granularity() const { return data_.delta_granularity; }
+
LayerTreeImpl* layer_tree_impl() { return layer_tree_impl_; }
ScrollStateData* data() { return &data_; }
diff --git a/chromium/cc/input/scrollbar.h b/chromium/cc/input/scrollbar.h
index ec23fef5f0d..7d0647ff78e 100644
--- a/chromium/cc/input/scrollbar.h
+++ b/chromium/cc/input/scrollbar.h
@@ -10,13 +10,21 @@
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
-static const int kPixelsPerLineStep = 40;
-static const float kMinFractionToStepWhenPaging = 0.875f;
+static constexpr int kPixelsPerLineStep = 40;
+static constexpr float kMinFractionToStepWhenPaging = 0.875f;
+
+// Autoscrolling (on the main thread) happens by applying a delta every 50ms.
+// Hence, pixels per second for a autoscroll cc animation can be calculated as:
+// autoscroll velocity = delta / 0.05 sec = delta x 20
+static constexpr float kAutoscrollMultiplier = 20.f;
+static constexpr base::TimeDelta kInitialAutoscrollTimerDelay =
+ base::TimeDelta::FromMilliseconds(250);
namespace cc {
enum ScrollbarOrientation { HORIZONTAL, VERTICAL };
enum ScrollDirection { SCROLL_BACKWARD, SCROLL_FORWARD };
+enum AutoScrollState { NO_AUTOSCROLL, AUTOSCROLL_FORWARD, AUTOSCROLL_BACKWARD };
enum ScrollbarPart {
THUMB,
diff --git a/chromium/cc/input/scrollbar_animation_controller.cc b/chromium/cc/input/scrollbar_animation_controller.cc
index 4b63b4bf9b7..bed51a0282d 100644
--- a/chromium/cc/input/scrollbar_animation_controller.cc
+++ b/chromium/cc/input/scrollbar_animation_controller.cc
@@ -55,8 +55,7 @@ ScrollbarAnimationController::ScrollbarAnimationController(
show_scrollbars_on_scroll_gesture_(false),
need_thinning_animation_(false),
is_mouse_down_(false),
- tickmarks_showing_(false),
- weak_factory_(this) {}
+ tickmarks_showing_(false) {}
ScrollbarAnimationController::ScrollbarAnimationController(
ElementId scroll_element_id,
@@ -78,8 +77,7 @@ ScrollbarAnimationController::ScrollbarAnimationController(
show_scrollbars_on_scroll_gesture_(true),
need_thinning_animation_(true),
is_mouse_down_(false),
- tickmarks_showing_(false),
- weak_factory_(this) {
+ tickmarks_showing_(false) {
vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create(
scroll_element_id, ScrollbarOrientation::VERTICAL, client,
thinning_duration);
diff --git a/chromium/cc/input/scrollbar_animation_controller.h b/chromium/cc/input/scrollbar_animation_controller.h
index f7a26c523f4..67a9ed5c8fc 100644
--- a/chromium/cc/input/scrollbar_animation_controller.h
+++ b/chromium/cc/input/scrollbar_animation_controller.h
@@ -169,7 +169,7 @@ class CC_EXPORT ScrollbarAnimationController {
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
horizontal_controller_;
- base::WeakPtrFactory<ScrollbarAnimationController> weak_factory_;
+ base::WeakPtrFactory<ScrollbarAnimationController> weak_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/input/scrollbar_controller.cc b/chromium/cc/input/scrollbar_controller.cc
index d29a2574cc6..46f4b21dbca 100644
--- a/chromium/cc/input/scrollbar_controller.cc
+++ b/chromium/cc/input/scrollbar_controller.cc
@@ -6,19 +6,40 @@
#include <algorithm>
+#include "base/cancelable_callback.h"
#include "cc/base/math_util.h"
#include "cc/input/scrollbar.h"
#include "cc/input/scrollbar_controller.h"
#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scroll_node.h"
namespace cc {
+ScrollbarController::~ScrollbarController() {
+ if (cancelable_autoscroll_task_) {
+ cancelable_autoscroll_task_->Cancel();
+ cancelable_autoscroll_task_.reset();
+ }
+}
+
ScrollbarController::ScrollbarController(
LayerTreeHostImpl* layer_tree_host_impl)
: layer_tree_host_impl_(layer_tree_host_impl),
scrollbar_scroll_is_active_(false),
thumb_drag_in_progress_(false),
+ autoscroll_state_(AutoScrollState::NO_AUTOSCROLL),
currently_captured_scrollbar_(nullptr),
- previous_pointer_position_(gfx::PointF(0, 0)) {}
+ previous_pointer_position_(gfx::PointF(0, 0)),
+ cancelable_autoscroll_task_(nullptr) {}
+
+void ScrollbarController::WillBeginImplFrame() {
+ // TODO(arakeri): Revisit this when addressing crbug.com/967004. The
+ // animations need to be aborted/restarted based on the pointer location (i.e
+ // leaving/entering the track/arrows, reaching the track end etc). The
+ // autoscroll_state_ however, needs to be reset on pointer changes.
+ if (autoscroll_state_ != AutoScrollState::NO_AUTOSCROLL &&
+ ShouldCancelTrackAutoscroll())
+ layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
+}
// Performs hit test and prepares scroll deltas that will be used by GSB and
// GSU.
@@ -35,11 +56,14 @@ InputHandlerPointerResult ScrollbarController::HandleMouseDown(
currently_captured_scrollbar_ = layer_impl->ToScrollbarLayer();
scroll_result.type = PointerResultType::kScrollbarScroll;
layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
- scroll_result.scroll_offset =
- GetScrollDeltaFromPointerDown(position_in_widget);
+ ScrollbarPart scrollbar_part =
+ GetScrollbarPartFromPointerDown(position_in_widget);
+ scroll_result.scroll_offset = GetScrollOffsetForScrollbarPart(
+ scrollbar_part, currently_captured_scrollbar_->orientation());
previous_pointer_position_ = position_in_widget;
scrollbar_scroll_is_active_ = true;
- if (thumb_drag_in_progress_) {
+ if (scrollbar_part == ScrollbarPart::THUMB) {
+ thumb_drag_in_progress_ = true;
scroll_result.scroll_units =
ui::input_types::ScrollGranularity::kScrollByPrecisePixel;
} else {
@@ -49,12 +73,27 @@ InputHandlerPointerResult ScrollbarController::HandleMouseDown(
ui::input_types::ScrollGranularity::kScrollByPixel;
}
+ // Thumb drag is the only scrollbar manipulation that cannot produce an
+ // autoscroll. All other interactions like clicking on arrows/trackparts have
+ // the potential of initiating an autoscroll (if held down long enough).
+ if (!scroll_result.scroll_offset.IsZero() && !thumb_drag_in_progress_) {
+ cancelable_autoscroll_task_ = std::make_unique<base::CancelableClosure>(
+ base::Bind(&ScrollbarController::StartAutoScrollAnimation,
+ base::Unretained(this), scroll_result.scroll_offset,
+ currently_captured_scrollbar_->scroll_element_id()));
+ layer_tree_host_impl_->task_runner_provider()
+ ->ImplThreadTaskRunner()
+ ->PostDelayedTask(FROM_HERE, cancelable_autoscroll_task_->callback(),
+ kInitialAutoscrollTimerDelay);
+ }
return scroll_result;
}
// Performs hit test and prepares scroll deltas that will be used by GSU.
InputHandlerPointerResult ScrollbarController::HandleMouseMove(
const gfx::PointF position_in_widget) {
+ const gfx::PointF previous_pointer_position = previous_pointer_position_;
+ previous_pointer_position_ = position_in_widget;
InputHandlerPointerResult scroll_result;
if (!thumb_drag_in_progress_)
return scroll_result;
@@ -64,10 +103,10 @@ InputHandlerPointerResult ScrollbarController::HandleMouseMove(
currently_captured_scrollbar_->orientation();
if (orientation == ScrollbarOrientation::VERTICAL)
scroll_result.scroll_offset.set_y(position_in_widget.y() -
- previous_pointer_position_.y());
+ previous_pointer_position.y());
else
scroll_result.scroll_offset.set_x(position_in_widget.x() -
- previous_pointer_position_.x());
+ previous_pointer_position.x());
LayerImpl* owner_scroll_layer =
layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId(
@@ -129,7 +168,6 @@ InputHandlerPointerResult ScrollbarController::HandleMouseMove(
(scrollbar_track_length - scrollbar_thumb_length)) *
layer_tree_host_impl_->active_tree()->device_scale_factor();
scroll_result.scroll_offset.Scale(scaled_scroller_to_scrollbar_ratio);
- previous_pointer_position_ = position_in_widget;
// Thumb drags have more granularity and are purely dependent on the pointer
// movement. Hence we use kPrecisePixel when dragging the thumb.
scroll_result.scroll_units =
@@ -138,6 +176,95 @@ InputHandlerPointerResult ScrollbarController::HandleMouseMove(
return scroll_result;
}
+bool ScrollbarController::ShouldCancelTrackAutoscroll() {
+ // Should only ever be called if an autoscroll is in progress.
+ DCHECK(autoscroll_state_ != AutoScrollState::NO_AUTOSCROLL);
+
+ layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
+ const ScrollbarOrientation orientation =
+ currently_captured_scrollbar_->orientation();
+ const gfx::Rect thumb_quad =
+ currently_captured_scrollbar_->ComputeThumbQuadRect();
+
+ bool clipped;
+ gfx::PointF scroller_relative_position(
+ GetScrollbarRelativePosition(previous_pointer_position_, &clipped));
+
+ if (clipped)
+ return false;
+
+ // Based on the orientation of the scrollbar and the direction of the
+ // autoscroll, the code below makes a decision of whether the track autoscroll
+ // should be canceled or not.
+ int thumb_start = 0;
+ int thumb_end = 0;
+ int pointer_position = 0;
+ if (orientation == ScrollbarOrientation::VERTICAL) {
+ thumb_start = thumb_quad.y();
+ thumb_end = thumb_quad.y() + thumb_quad.height();
+ pointer_position = scroller_relative_position.y();
+ } else {
+ thumb_start = thumb_quad.x();
+ thumb_end = thumb_quad.x() + thumb_quad.width();
+ pointer_position = scroller_relative_position.x();
+ }
+
+ if ((autoscroll_state_ == AutoScrollState::AUTOSCROLL_FORWARD &&
+ thumb_end > pointer_position) ||
+ (autoscroll_state_ == AutoScrollState::AUTOSCROLL_BACKWARD &&
+ thumb_start < pointer_position))
+ return true;
+
+ return false;
+}
+
+void ScrollbarController::StartAutoScrollAnimation(
+ gfx::ScrollOffset scroll_offset,
+ ElementId element_id) {
+ // scroll_node is set up while handling GSB. If there's no node to scroll, we
+ // don't need to create any animation for it.
+ ScrollTree& scroll_tree =
+ layer_tree_host_impl_->active_tree()->property_trees()->scroll_tree;
+ ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id);
+
+ if (!(scroll_node && scrollbar_scroll_is_active_))
+ return;
+
+ layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
+ ScrollbarOrientation orientation =
+ currently_captured_scrollbar_->orientation();
+ // TODO(arakeri): The animation needs to be readjusted if the scroller length
+ // changes. Tracked here: crbug.com/972485
+ float scroll_layer_length =
+ currently_captured_scrollbar_->scroll_layer_length();
+
+ gfx::ScrollOffset current_offset =
+ scroll_tree.current_scroll_offset(scroll_node->element_id);
+ gfx::Vector2dF target_offset;
+
+ // Determine the max offset for the scroll based on the scrolling direction.
+ // Negative scroll_delta indicates backwards scrolling whereas a positive
+ // scroll_delta indicates forwards scrolling.
+ float scroll_delta = 0;
+ if (orientation == ScrollbarOrientation::VERTICAL) {
+ DCHECK_NE(scroll_offset.y(), 0);
+ scroll_delta = scroll_offset.y();
+ float final_offset = scroll_delta < 0 ? 0 : scroll_layer_length;
+ target_offset = gfx::Vector2dF(current_offset.x(), final_offset);
+ } else {
+ DCHECK_NE(scroll_offset.x(), 0);
+ scroll_delta = scroll_offset.x();
+ float final_offset = scroll_delta < 0 ? 0 : scroll_layer_length;
+ target_offset = gfx::Vector2dF(final_offset, current_offset.y());
+ }
+
+ autoscroll_state_ = scroll_delta < 0 ? AutoScrollState::AUTOSCROLL_BACKWARD
+ : AutoScrollState::AUTOSCROLL_FORWARD;
+ float autoscroll_velocity = std::abs(scroll_delta) * kAutoscrollMultiplier;
+ layer_tree_host_impl_->AutoScrollAnimationCreate(scroll_node, target_offset,
+ autoscroll_velocity);
+}
+
// Performs hit test and prepares scroll deltas that will be used by GSE.
InputHandlerPointerResult ScrollbarController::HandleMouseUp(
const gfx::PointF position_in_widget) {
@@ -146,7 +273,20 @@ InputHandlerPointerResult ScrollbarController::HandleMouseUp(
scrollbar_scroll_is_active_ = false;
scroll_result.type = PointerResultType::kScrollbarScroll;
}
+
+ // TODO(arakeri): This needs to be moved to ScrollOffsetAnimationsImpl as it
+ // has knowledge about what type of animation is running. crbug.com/976353
+ // Only abort the animation if it is an "autoscroll" animation.
+ if (autoscroll_state_ != AutoScrollState::NO_AUTOSCROLL)
+ layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
+
+ if (cancelable_autoscroll_task_) {
+ cancelable_autoscroll_task_->Cancel();
+ cancelable_autoscroll_task_.reset();
+ }
+
thumb_drag_in_progress_ = false;
+ autoscroll_state_ = AutoScrollState::NO_AUTOSCROLL;
return scroll_result;
}
@@ -195,31 +335,41 @@ int ScrollbarController::GetScrollDeltaForScrollbarPart(
layer_tree_host_impl_->active_tree()->device_scale_factor();
}
-// Determines the scroll offsets based on hit test results.
-gfx::ScrollOffset ScrollbarController::GetScrollDeltaFromPointerDown(
- const gfx::PointF position_in_widget) {
- const ScrollbarOrientation orientation =
- currently_captured_scrollbar_->orientation();
-
- // position_in_widget needs to be transformed and made relative to the
- // scrollbar layer because hit testing assumes layer relative coordinates.
- ScrollbarPart scrollbar_part = ScrollbarPart::NO_PART;
+gfx::PointF ScrollbarController::GetScrollbarRelativePosition(
+ const gfx::PointF position_in_widget,
+ bool* clipped) {
gfx::Transform inverse_screen_space_transform(
gfx::Transform::kSkipInitialization);
if (!currently_captured_scrollbar_->ScreenSpaceTransform().GetInverse(
&inverse_screen_space_transform))
- return gfx::ScrollOffset(0, 0);
+ return gfx::PointF(0, 0);
- bool clipped;
- gfx::PointF scroller_relative_position(MathUtil::ProjectPoint(
- inverse_screen_space_transform, position_in_widget, &clipped));
+ return gfx::PointF(MathUtil::ProjectPoint(inverse_screen_space_transform,
+ position_in_widget, clipped));
+}
+
+// Determines the ScrollbarPart based on the position_in_widget.
+ScrollbarPart ScrollbarController::GetScrollbarPartFromPointerDown(
+ const gfx::PointF position_in_widget) {
+ // position_in_widget needs to be transformed and made relative to the
+ // scrollbar layer because hit testing assumes layer relative coordinates.
+ bool clipped = false;
+
+ const gfx::PointF scroller_relative_position(
+ GetScrollbarRelativePosition(position_in_widget, &clipped));
if (clipped)
- return gfx::ScrollOffset(0, 0);
+ return ScrollbarPart::NO_PART;
- scrollbar_part = currently_captured_scrollbar_->IdentifyScrollbarPart(
+ return currently_captured_scrollbar_->IdentifyScrollbarPart(
scroller_relative_position);
+}
+// Determines the scroll offsets based on the ScrollbarPart and the scrollbar
+// orientation.
+gfx::ScrollOffset ScrollbarController::GetScrollOffsetForScrollbarPart(
+ const ScrollbarPart scrollbar_part,
+ const ScrollbarOrientation orientation) {
float scroll_delta = GetScrollDeltaForScrollbarPart(scrollbar_part);
// See CreateScrollStateForGesture for more information on how these values
@@ -232,9 +382,6 @@ gfx::ScrollOffset ScrollbarController::GetScrollDeltaFromPointerDown(
return orientation == ScrollbarOrientation::VERTICAL
? gfx::ScrollOffset(0, scroll_delta) // Down arrow
: gfx::ScrollOffset(scroll_delta, 0); // Right arrow
- } else if (scrollbar_part == ScrollbarPart::THUMB) {
- // Offsets are calculated in HandleMouseMove.
- thumb_drag_in_progress_ = true;
} else if (scrollbar_part == ScrollbarPart::BACK_TRACK) {
return orientation == ScrollbarOrientation::VERTICAL
? gfx::ScrollOffset(0, -scroll_delta) // Track click up
diff --git a/chromium/cc/input/scrollbar_controller.h b/chromium/cc/input/scrollbar_controller.h
index 3ce462461bf..550e63ef1ba 100644
--- a/chromium/cc/input/scrollbar_controller.h
+++ b/chromium/cc/input/scrollbar_controller.h
@@ -18,7 +18,7 @@ namespace cc {
class CC_EXPORT ScrollbarController {
public:
explicit ScrollbarController(LayerTreeHostImpl*);
- virtual ~ScrollbarController() = default;
+ virtual ~ScrollbarController();
InputHandlerPointerResult HandleMouseDown(
const gfx::PointF position_in_widget);
@@ -26,14 +26,38 @@ class CC_EXPORT ScrollbarController {
const gfx::PointF position_in_widget);
InputHandlerPointerResult HandleMouseUp(const gfx::PointF position_in_widget);
+ // scroll_offset is the delta from the initial click. This is needed to
+ // determine whether we should set up the autoscrolling in the forwards or the
+ // backwards direction and the speed of the animation.
+ void StartAutoScrollAnimation(gfx::ScrollOffset scroll_offset,
+ ElementId element_id);
+ bool ScrollbarScrollIsActive() { return scrollbar_scroll_is_active_; }
+ ScrollbarOrientation orientation() {
+ return currently_captured_scrollbar_->orientation();
+ }
+
+ void WillBeginImplFrame();
+
private:
- // Returns a gfx::ScrollOffset object which contains scroll deltas for the
- // synthetic Gesture events.
- gfx::ScrollOffset GetScrollDeltaFromPointerDown(
+ // Returns the hit tested ScrollbarPart based on the position_in_widget.
+ ScrollbarPart GetScrollbarPartFromPointerDown(
const gfx::PointF position_in_widget);
+
+ // Returns scroll offsets based on which ScrollbarPart was hit tested.
+ gfx::ScrollOffset GetScrollOffsetForScrollbarPart(
+ const ScrollbarPart scrollbar_part,
+ const ScrollbarOrientation orientation);
+
LayerImpl* GetLayerHitByPoint(const gfx::PointF position_in_widget);
int GetScrollDeltaForScrollbarPart(ScrollbarPart scrollbar_part);
+ // Makes position_in_widget relative to the scrollbar.
+ gfx::PointF GetScrollbarRelativePosition(const gfx::PointF position_in_widget,
+ bool* clipped);
+
+ // Decides whether a track autoscroll should be aborted.
+ bool ShouldCancelTrackAutoscroll();
+
LayerTreeHostImpl* layer_tree_host_impl_;
// Used to safeguard against firing GSE without firing GSB and GSU. For
@@ -43,10 +67,17 @@ class CC_EXPORT ScrollbarController {
// Used to tell if the scrollbar thumb is getting dragged.
bool thumb_drag_in_progress_;
+
+ // "Autoscroll" here means the continuous scrolling that occurs when the
+ // pointer is held down on a hit-testable area of the scrollbar such as an
+ // arrows of the track itself.
+ AutoScrollState autoscroll_state_;
const ScrollbarLayerImplBase* currently_captured_scrollbar_;
// This is relative to the RenderWidget's origin.
gfx::PointF previous_pointer_position_;
+
+ std::unique_ptr<base::CancelableClosure> cancelable_autoscroll_task_;
};
} // namespace cc
diff --git a/chromium/cc/layers/append_quads_data.h b/chromium/cc/layers/append_quads_data.h
index a681a97b489..02545c2383b 100644
--- a/chromium/cc/layers/append_quads_data.h
+++ b/chromium/cc/layers/append_quads_data.h
@@ -11,6 +11,7 @@
#include "base/optional.h"
#include "cc/cc_export.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "ui/gfx/geometry/rect.h"
namespace cc {
@@ -44,6 +45,10 @@ class CC_EXPORT AppendQuadsData {
// active CompositorFrames so that this CompositorFrame can
// activate.
std::vector<viz::SurfaceId> activation_dependencies;
+
+ // If the layer is a MirrorLayer, this will represent its visible boundaries
+ // in target space.
+ gfx::Rect mirror_rect;
};
} // namespace cc
diff --git a/chromium/cc/layers/draw_properties.cc b/chromium/cc/layers/draw_properties.cc
index 0cff4994c1d..b998cff755b 100644
--- a/chromium/cc/layers/draw_properties.cc
+++ b/chromium/cc/layers/draw_properties.cc
@@ -6,10 +6,7 @@
namespace cc {
-DrawProperties::DrawProperties()
- : opacity(0.f),
- screen_space_transform_is_animating(false),
- is_clipped(false) {}
+DrawProperties::DrawProperties() = default;
DrawProperties::~DrawProperties() = default;
diff --git a/chromium/cc/layers/draw_properties.h b/chromium/cc/layers/draw_properties.h
index 1b96435e988..b241728724c 100644
--- a/chromium/cc/layers/draw_properties.h
+++ b/chromium/cc/layers/draw_properties.h
@@ -35,19 +35,19 @@ struct CC_EXPORT DrawProperties {
// DrawProperties::opacity may be different than LayerImpl::opacity,
// particularly in the case when a RenderSurface re-parents the layer's
// opacity, or when opacity is compounded by the hierarchy.
- float opacity;
+ float opacity = 0.f;
// Whether the layer has a potentially animating transform in its chain of
// transforms to the screen. This is essentially a cache of the transform
// node's potentially-animated status.
- bool screen_space_transform_is_animating;
+ bool screen_space_transform_is_animating = false;
// True if the layer needs to be clipped by clip_rect.
- bool is_clipped;
+ bool is_clipped = false;
// If set, it makes the layer's rounded corner not trigger a render surface if
// possible.
- bool is_fast_rounded_corner;
+ bool is_fast_rounded_corner = false;
// This rect is a bounding box around what part of the layer is visible, in
// the layer's coordinate space.
diff --git a/chromium/cc/layers/heads_up_display_layer.cc b/chromium/cc/layers/heads_up_display_layer.cc
index e291e6ee99a..d1ac009c6de 100644
--- a/chromium/cc/layers/heads_up_display_layer.cc
+++ b/chromium/cc/layers/heads_up_display_layer.cc
@@ -82,6 +82,7 @@ void HeadsUpDisplayLayer::PushPropertiesTo(LayerImpl* layer) {
layer_impl->SetHUDTypeface(typeface_);
layer_impl->SetLayoutShiftRects(layout_shift_rects_);
+ layout_shift_rects_.clear();
}
} // namespace cc
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index 75431c15d8f..f98f34286bb 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -107,8 +107,7 @@ HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(LayerTreeImpl* tree_impl,
: LayerImpl(tree_impl, id),
internal_contents_scale_(1.f),
fps_graph_(60.0, 80.0),
- paint_time_graph_(16.0, 48.0),
- fade_step_(0) {}
+ paint_time_graph_(16.0, 48.0) {}
HeadsUpDisplayLayerImpl::~HeadsUpDisplayLayerImpl() {
ReleaseResources();
@@ -188,7 +187,7 @@ void HeadsUpDisplayLayerImpl::AppendQuads(viz::RenderPass* render_pass,
viz::SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
PopulateScaledSharedQuadState(shared_quad_state, internal_contents_scale_,
- internal_contents_scale_, contents_opaque());
+ contents_opaque());
// Appends a dummy quad here, which will be updated later once the resource
// is ready in UpdateHudTexture(). We don't add a TextureDrawQuad directly
@@ -321,14 +320,13 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
auto backing = std::make_unique<HudSoftwareBacking>();
backing->layer_tree_frame_sink = layer_tree_frame_sink;
backing->shared_bitmap_id = viz::SharedBitmap::GenerateId();
- base::MappedReadOnlyRegion mapped_region =
+ base::MappedReadOnlyRegion shm =
viz::bitmap_allocation::AllocateSharedBitmap(pool_resource.size(),
pool_resource.format());
- backing->shared_mapping = std::move(mapped_region.mapping);
+ backing->shared_mapping = std::move(shm.mapping);
- layer_tree_frame_sink->DidAllocateSharedBitmap(
- viz::bitmap_allocation::ToMojoHandle(std::move(mapped_region.region)),
- backing->shared_bitmap_id);
+ layer_tree_frame_sink->DidAllocateSharedBitmap(std::move(shm.region),
+ backing->shared_bitmap_id);
pool_resource.set_software_backing(std::move(backing));
}
@@ -483,7 +481,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
/*background_color=*/SK_ColorTRANSPARENT, vertex_opacity,
/*flipped=*/false,
/*nearest_neighbor=*/false, /*secure_output_only=*/false,
- ui::ProtectedVideoType::kClear);
+ gfx::ProtectedVideoType::kClear);
ValidateQuadResources(quad);
break;
}
@@ -532,6 +530,7 @@ void HeadsUpDisplayLayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer_impl->SetHUDTypeface(typeface_);
layer_impl->SetLayoutShiftRects(layout_shift_rects_);
+ layout_shift_rects_.clear();
}
void HeadsUpDisplayLayerImpl::UpdateHudContents() {
@@ -983,6 +982,7 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
const std::vector<DebugRect>& debug_rects = debug_rect_history->debug_rects();
std::vector<DebugRect> new_paint_rects;
+ std::vector<DebugRect> new_layout_shift_rects;
for (size_t i = 0; i < debug_rects.size(); ++i) {
SkColor stroke_color = 0;
@@ -992,8 +992,8 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
switch (debug_rects[i].type) {
case LAYOUT_SHIFT_RECT_TYPE:
- // TODO(rnasri@): Handle layout shift rects drawing.
- break;
+ new_layout_shift_rects.push_back(debug_rects[i]);
+ continue;
case PAINT_RECT_TYPE:
new_paint_rects.push_back(debug_rects[i]);
continue;
@@ -1051,17 +1051,32 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
if (new_paint_rects.size()) {
paint_rects_.swap(new_paint_rects);
- fade_step_ = DebugColors::kFadeSteps;
+ paint_rects_fade_step_ = DebugColors::kFadeSteps;
}
- if (fade_step_ > 0) {
- fade_step_--;
+ if (paint_rects_fade_step_ > 0) {
+ paint_rects_fade_step_--;
for (size_t i = 0; i < paint_rects_.size(); ++i) {
DrawDebugRect(canvas, &flags, paint_rects_[i],
- DebugColors::PaintRectBorderColor(fade_step_),
- DebugColors::PaintRectFillColor(fade_step_),
+ DebugColors::PaintRectBorderColor(paint_rects_fade_step_),
+ DebugColors::PaintRectFillColor(paint_rects_fade_step_),
DebugColors::PaintRectBorderWidth(), "");
}
}
+
+ if (new_layout_shift_rects.size()) {
+ layout_shift_debug_rects_.swap(new_layout_shift_rects);
+ layout_shift_rects_fade_step_ = DebugColors::kFadeSteps;
+ }
+ if (layout_shift_rects_fade_step_ > 0) {
+ layout_shift_rects_fade_step_--;
+ for (size_t i = 0; i < layout_shift_debug_rects_.size(); ++i) {
+ DrawDebugRect(
+ canvas, &flags, layout_shift_debug_rects_[i],
+ DebugColors::LayoutShiftRectBorderColor(),
+ DebugColors::LayoutShiftRectFillColor(layout_shift_rects_fade_step_),
+ DebugColors::LayoutShiftRectBorderWidth(), "");
+ }
+ }
}
const char* HeadsUpDisplayLayerImpl::LayerTypeAsString() const {
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h
index 4b1f4bf6ee2..e0784ff4b21 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.h
+++ b/chromium/cc/layers/heads_up_display_layer_impl.h
@@ -61,7 +61,9 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
gfx::Rect GetEnclosingRectInTargetSpace() const override;
- bool IsAnimatingHUDContents() const { return fade_step_ > 0; }
+ bool IsAnimatingHUDContents() const {
+ return paint_rects_fade_step_ > 0 || layout_shift_rects_fade_step_ > 0;
+ }
void SetHUDTypeface(sk_sp<SkTypeface> typeface);
void SetLayoutShiftRects(const std::vector<gfx::Rect>& rects);
@@ -158,8 +160,10 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
Graph fps_graph_;
Graph paint_time_graph_;
MemoryHistory::Entry memory_entry_;
- int fade_step_;
+ int paint_rects_fade_step_ = 0;
+ int layout_shift_rects_fade_step_ = 0;
std::vector<DebugRect> paint_rects_;
+ std::vector<DebugRect> layout_shift_debug_rects_;
base::TimeTicks time_of_last_graph_update_;
};
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index 24db5b0a3cc..4fcd802446e 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -23,8 +23,8 @@
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer.h"
#include "cc/tiles/frame_viewer_instrumentation.h"
+#include "cc/trees/clip_node.h"
#include "cc/trees/draw_property_utils.h"
-#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/mutator_host.h"
@@ -71,7 +71,8 @@ Layer::Inputs::Inputs(int layer_id)
has_will_change_transform_hint(false),
trilinear_filtering(false),
hide_layer_and_subtree(false),
- overscroll_behavior(OverscrollBehavior::kOverscrollBehaviorTypeAuto) {}
+ overscroll_behavior(OverscrollBehavior::kOverscrollBehaviorTypeAuto),
+ mirror_count(0) {}
Layer::Inputs::~Inputs() = default;
@@ -101,6 +102,7 @@ Layer::Layer()
may_contain_video_(false),
needs_show_scrollbars_(false),
has_transform_node_(false),
+ has_clip_node_(false),
subtree_has_copy_request_(false),
safe_opaque_background_color_(0),
compositing_reasons_(0),
@@ -214,7 +216,7 @@ bool Layer::IsPropertyChangeAllowed() const {
}
void Layer::CaptureContent(const gfx::Rect& rect,
- std::vector<NodeHolder>* content) {}
+ std::vector<NodeId>* content) {}
sk_sp<SkPicture> Layer::GetPicture() const {
return nullptr;
@@ -535,10 +537,63 @@ void Layer::SetMasksToBounds(bool masks_to_bounds) {
SetSubtreePropertyChanged();
}
+void Layer::SetClipRect(const gfx::Rect& clip_rect) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (inputs_.clip_rect == clip_rect)
+ return;
+ inputs_.clip_rect = clip_rect;
+
+ // If the clip bounds have been cleared, the property trees needs a rebuild.
+ const bool force_rebuild = clip_rect.IsEmpty() || !has_clip_node_;
+
+ SetSubtreePropertyChanged();
+ if (clip_tree_index() != ClipTree::kInvalidNodeId && !force_rebuild) {
+ PropertyTrees* property_trees = layer_tree_host_->property_trees();
+ gfx::RectF effective_clip_rect = EffectiveClipRect();
+ if (ClipNode* node = property_trees->clip_tree.Node(clip_tree_index())) {
+ node->clip = effective_clip_rect;
+ node->clip += offset_to_transform_parent();
+ property_trees->clip_tree.set_needs_update(true);
+ }
+ if (HasRoundedCorner() &&
+ effect_tree_index() != EffectTree::kInvalidNodeId) {
+ if (EffectNode* node =
+ property_trees->effect_tree.Node(effect_tree_index())) {
+ node->rounded_corner_bounds =
+ gfx::RRectF(effective_clip_rect, corner_radii());
+ node->effect_changed = true;
+ property_trees->effect_tree.set_needs_update(true);
+ }
+ }
+ } else {
+ SetPropertyTreesNeedRebuild();
+ }
+ SetNeedsCommit();
+}
+
+gfx::RectF Layer::EffectiveClipRect() {
+ // If this does not have a clip rect set, then the subtree is clipped by
+ // the bounds.
+ const gfx::RectF layer_bounds = gfx::RectF(gfx::SizeF(bounds()));
+ if (clip_rect().IsEmpty())
+ return layer_bounds;
+
+ const gfx::RectF clip_rect_f(clip_rect());
+
+ // Layer needs to clip to its bounds as well apply a clip rect. Intersect the
+ // two to get the effective clip.
+ if (masks_to_bounds() || mask_layer() || filters().HasFilterThatMovesPixels())
+ return gfx::IntersectRects(layer_bounds, clip_rect_f);
+
+ // Clip rect is the only clip effecting the layer.
+ return clip_rect_f;
+}
+
void Layer::SetMaskLayer(PictureLayer* mask_layer) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.mask_layer.get() == mask_layer)
return;
+ DCHECK(!layer_tree_host_ || !layer_tree_host_->IsUsingLayerLists());
if (inputs_.mask_layer.get()) {
DCHECK_EQ(this, inputs_.mask_layer->parent());
inputs_.mask_layer->RemoveFromParent();
@@ -551,15 +606,8 @@ void Layer::SetMaskLayer(PictureLayer* mask_layer) {
inputs_.mask_layer->RemoveFromParent();
DCHECK(!inputs_.mask_layer->parent());
inputs_.mask_layer->SetParent(this);
- if (inputs_.filters.IsEmpty() && inputs_.backdrop_filters.IsEmpty() &&
- (!layer_tree_host_ ||
- layer_tree_host_->GetSettings().enable_mask_tiling)) {
- inputs_.mask_layer->SetLayerMaskType(
- Layer::LayerMaskType::MULTI_TEXTURE_MASK);
- } else {
- inputs_.mask_layer->SetLayerMaskType(
- Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
- }
+ inputs_.mask_layer->SetLayerMaskType(
+ Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
}
SetSubtreePropertyChanged();
SetNeedsFullTreeSync();
@@ -570,10 +618,6 @@ void Layer::SetFilters(const FilterOperations& filters) {
if (inputs_.filters == filters)
return;
inputs_.filters = filters;
- if (inputs_.mask_layer && !filters.IsEmpty()) {
- inputs_.mask_layer->SetLayerMaskType(
- Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
- }
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
@@ -585,13 +629,6 @@ void Layer::SetBackdropFilters(const FilterOperations& filters) {
return;
inputs_.backdrop_filters = filters;
- // We will not set the mask type to MULTI_TEXTURE_MASK if the mask layer's
- // filters are removed, because we do not want to reraster if the filters are
- // being animated.
- if (inputs_.mask_layer && !filters.IsEmpty()) {
- inputs_.mask_layer->SetLayerMaskType(
- Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
- }
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
@@ -627,7 +664,17 @@ void Layer::SetRoundedCorner(const gfx::RoundedCornersF& corner_radii) {
inputs_.corner_radii = corner_radii;
SetSubtreePropertyChanged();
SetNeedsCommit();
- SetPropertyTreesNeedRebuild();
+ PropertyTrees* property_trees = layer_tree_host_->property_trees();
+ EffectNode* node = nullptr;
+ if (effect_tree_index() != EffectTree::kInvalidNodeId &&
+ (node = property_trees->effect_tree.Node(effect_tree_index()))) {
+ node->rounded_corner_bounds =
+ gfx::RRectF(EffectiveClipRect(), corner_radii);
+ node->effect_changed = true;
+ property_trees->effect_tree.set_needs_update(true);
+ } else {
+ SetPropertyTreesNeedRebuild();
+ }
}
void Layer::SetIsFastRoundedCorner(bool enable) {
@@ -1140,6 +1187,23 @@ void Layer::SetCacheRenderSurface(bool cache) {
SetNeedsCommit();
}
+RenderSurfaceReason Layer::GetRenderSurfaceReason() const {
+ if (!layer_tree_host_)
+ return RenderSurfaceReason::kNone;
+ PropertyTrees* property_trees = layer_tree_host_->property_trees();
+ DCHECK(!property_trees->needs_rebuild);
+ EffectNode* effect_node =
+ property_trees->effect_tree.Node(this->effect_tree_index());
+
+ // Effect node can also be the effect node of an ancestor layer.
+ // Check if this effect node was created for this layer specifically.
+ if (!effect_node ||
+ (parent_ && this->effect_tree_index() == parent_->effect_tree_index())) {
+ return RenderSurfaceReason::kNone;
+ }
+ return effect_node->render_surface_reason;
+}
+
void Layer::SetForceRenderSurfaceForTesting(bool force) {
DCHECK(IsPropertyChangeAllowed());
if (force_render_surface_for_testing_ == force)
@@ -1244,6 +1308,7 @@ void Layer::SetOffsetToTransformParent(gfx::Vector2dF offset) {
return;
offset_to_transform_parent_ = offset;
SetNeedsPushProperties();
+ SetSubtreePropertyChanged();
}
void Layer::InvalidatePropertyTreesIndices() {
@@ -1458,6 +1523,7 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetMasksToBounds(inputs_.masks_to_bounds);
layer->SetNonFastScrollableRegion(inputs_.non_fast_scrollable_region);
layer->SetTouchActionRegion(inputs_.touch_action_region);
+ layer->SetMirrorCount(inputs_.mirror_count);
// TODO(sunxd): Pass the correct region for wheel event handlers, see
// https://crbug.com/841364.
EventListenerProperties mouse_wheel_props =
@@ -1651,6 +1717,27 @@ void Layer::SetTrilinearFiltering(bool trilinear_filtering) {
SetNeedsCommit();
}
+void Layer::IncrementMirrorCount() {
+ SetMirrorCount(mirror_count() + 1);
+}
+
+void Layer::DecrementMirrorCount() {
+ SetMirrorCount(mirror_count() - 1);
+}
+
+void Layer::SetMirrorCount(int mirror_count) {
+ if (inputs_.mirror_count == mirror_count)
+ return;
+
+ DCHECK_LE(0, mirror_count);
+ bool was_mirrored = inputs_.mirror_count > 0;
+ inputs_.mirror_count = mirror_count;
+ bool is_mirrored = inputs_.mirror_count > 0;
+ if (was_mirrored != is_mirrored)
+ SetPropertyTreesNeedRebuild();
+ SetNeedsPushProperties();
+}
+
ElementListType Layer::GetElementTypeForAnimation() const {
return ElementListType::ACTIVE;
}
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index 04740451da9..ba71871f25e 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -26,9 +26,10 @@
#include "cc/layers/layer_collections.h"
#include "cc/layers/layer_position_constraint.h"
#include "cc/layers/touch_action_region.h"
+#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
#include "cc/paint/paint_record.h"
-#include "cc/trees/element_id.h"
+#include "cc/trees/effect_node.h"
#include "cc/trees/property_tree.h"
#include "cc/trees/target_property.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -77,7 +78,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// describe how the mask would be generated as a texture in that case.
enum LayerMaskType {
NOT_MASK = 0,
- MULTI_TEXTURE_MASK,
SINGLE_TEXTURE_MASK,
};
@@ -215,6 +215,15 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void SetMasksToBounds(bool masks_to_bounds);
bool masks_to_bounds() const { return inputs_.masks_to_bounds; }
+ // Set or get the clip rect for this layer. |clip_rect| is relative to |this|
+ // layer. If you are trying to clip the subtree to the bounds of this layer,
+ // SetMasksToBounds() would be a better alternative.
+ void SetClipRect(const gfx::Rect& clip_rect);
+ const gfx::Rect& clip_rect() const { return inputs_.clip_rect; }
+
+ // Returns the bounds which is clipped by the clip rect.
+ gfx::RectF EffectiveClipRect();
+
// Set or get a layer that is not an ancestor of this layer, but which should
// be clipped to this layer's bounds if SetMasksToBounds() is set to true.
// The parent layer does *not* retain ownership of a reference on this layer.
@@ -250,6 +259,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// Set or get the rounded corner radii which is applied to the layer and its
// subtree (as if they are together as a single composited entity) when
// blitting into their target. Setting this makes the layer masked to bounds.
+ // If the layer has a clip of its own, the rounded corner will be applied
+ // along the layer's clip rect corners.
void SetRoundedCorner(const gfx::RoundedCornersF& corner_radii);
const gfx::RoundedCornersF& corner_radii() const {
return inputs_.corner_radii;
@@ -321,6 +332,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
return inputs_.backdrop_filter_bounds;
}
+ const ElementId backdrop_mask_element_id() const {
+ return inputs_.backdrop_mask_element_id;
+ }
+
void SetBackdropFilterQuality(const float quality);
float backdrop_filter_quality() const {
return inputs_.backdrop_filter_quality;
@@ -508,6 +523,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void SetCacheRenderSurface(bool cache_render_surface);
bool cache_render_surface() const { return cache_render_surface_; }
+ // If the layer induces a render surface, this returns the cause for the
+ // render surface. If the layer does not induce a render surface, this returns
+ // kNone.
+ RenderSurfaceReason GetRenderSurfaceReason() const;
+
// Set or get if the layer and its subtree will be drawn through an
// intermediate texture, called a RenderSurface. This mimics the need
// for a RenderSurface that is caused by compositing effects such as masks
@@ -603,6 +623,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void SetHasTransformNode(bool val) { has_transform_node_ = val; }
bool has_transform_node() { return has_transform_node_; }
+ // This value indicates whether a clip node was created for |this| layer.
+ void SetHasClipNode(bool val) { has_clip_node_ = val; }
+
// Sets that the content shown in this layer may be a video. This may be used
// by the system compositor to distinguish between animations updating the
// screen and video, which the user would be watching. This allows
@@ -634,13 +657,18 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void SetTrilinearFiltering(bool trilinear_filtering);
bool trilinear_filtering() const { return inputs_.trilinear_filtering; }
+ // Increments/decrements/gets number of layers mirroring this layer.
+ void IncrementMirrorCount();
+ void DecrementMirrorCount();
+ int mirror_count() const { return inputs_.mirror_count; }
+
// Called on the scroll layer to trigger showing the overlay scrollbars.
void ShowScrollbars() { needs_show_scrollbars_ = true; }
// Captures text content within the given |rect| and returns the associated
- // NodeHolder in content.
+ // NodeId in |content|.
virtual void CaptureContent(const gfx::Rect& rect,
- std::vector<NodeHolder>* content);
+ std::vector<NodeId>* content);
// For tracing. Gets a recorded rasterization of this layer's contents that
// can be displayed inside representations of this layer. May return null, in
@@ -757,6 +785,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// layer's subtree, including itself. This causes the layer's subtree to be
// considered damaged and re-displayed to the user.
void SetSubtreePropertyChanged();
+ void ClearSubtreePropertyChangedForTesting() {
+ subtree_property_changed_ = false;
+ }
bool subtree_property_changed() const { return subtree_property_changed_; }
// Internal to property tree construction. Returns ElementListType::ACTIVE
@@ -913,6 +944,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// they are marked as needing to be rebuilt.
void UpdateScrollOffset(const gfx::ScrollOffset&);
+ void SetMirrorCount(int mirror_count);
+
// Encapsulates all data, callbacks or interfaces received from the embedder.
struct Inputs {
explicit Inputs(int layer_id);
@@ -926,6 +959,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
gfx::Size bounds;
bool masks_to_bounds;
+ gfx::Rect clip_rect;
scoped_refptr<PictureLayer> mask_layer;
@@ -960,6 +994,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
FilterOperations filters;
FilterOperations backdrop_filters;
base::Optional<gfx::RRectF> backdrop_filter_bounds;
+ ElementId backdrop_mask_element_id;
gfx::PointF filters_origin;
float backdrop_filter_quality;
@@ -1030,6 +1065,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
OverscrollBehavior overscroll_behavior;
base::Optional<SnapContainerData> snap_container_data;
+
+ int mirror_count;
};
Layer* parent_;
@@ -1058,6 +1095,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
bool may_contain_video_ : 1;
bool needs_show_scrollbars_ : 1;
bool has_transform_node_ : 1;
+ bool has_clip_node_ : 1;
// This value is valid only when LayerTreeHost::has_copy_request() is true
bool subtree_has_copy_request_ : 1;
SkColor safe_opaque_background_color_;
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index 86ccf0fc4aa..67a48733e6c 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -80,7 +80,8 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl,
scrollbars_hidden_(false),
needs_show_scrollbars_(false),
raster_even_if_not_drawn_(false),
- has_transform_node_(false) {
+ has_transform_node_(false),
+ mirror_count_(0) {
DCHECK_GT(layer_id_, 0);
DCHECK(layer_tree_impl_);
@@ -150,22 +151,32 @@ void LayerImpl::PopulateSharedQuadState(viz::SharedQuadState* state,
}
void LayerImpl::PopulateScaledSharedQuadState(viz::SharedQuadState* state,
- float layer_to_content_scale_x,
- float layer_to_content_scale_y,
+ float layer_to_content_scale,
bool contents_opaque) const {
+ gfx::Size scaled_bounds =
+ gfx::ScaleToCeiledSize(bounds(), layer_to_content_scale);
+ gfx::Rect scaled_visible_layer_rect =
+ gfx::ScaleToEnclosingRect(visible_layer_rect(), layer_to_content_scale);
+ scaled_visible_layer_rect.Intersect(gfx::Rect(scaled_bounds));
+
+ PopulateScaledSharedQuadStateWithContentRects(
+ state, layer_to_content_scale, gfx::Rect(scaled_bounds),
+ scaled_visible_layer_rect, contents_opaque);
+}
+
+void LayerImpl::PopulateScaledSharedQuadStateWithContentRects(
+ viz::SharedQuadState* state,
+ float layer_to_content_scale,
+ const gfx::Rect& content_rect,
+ const gfx::Rect& visible_content_rect,
+ bool contents_opaque) const {
gfx::Transform scaled_draw_transform =
draw_properties_.target_space_transform;
- scaled_draw_transform.Scale(SK_MScalar1 / layer_to_content_scale_x,
- SK_MScalar1 / layer_to_content_scale_y);
- gfx::Size scaled_bounds = gfx::ScaleToCeiledSize(
- bounds(), layer_to_content_scale_x, layer_to_content_scale_y);
- gfx::Rect scaled_visible_layer_rect = gfx::ScaleToEnclosingRect(
- visible_layer_rect(), layer_to_content_scale_x, layer_to_content_scale_y);
- scaled_visible_layer_rect.Intersect(gfx::Rect(scaled_bounds));
+ scaled_draw_transform.Scale(SK_MScalar1 / layer_to_content_scale,
+ SK_MScalar1 / layer_to_content_scale);
EffectNode* effect_node = GetEffectTree().Node(effect_tree_index_);
- state->SetAll(scaled_draw_transform, gfx::Rect(scaled_bounds),
- scaled_visible_layer_rect,
+ state->SetAll(scaled_draw_transform, content_rect, visible_content_rect,
draw_properties().rounded_corner_bounds,
draw_properties().clip_rect, draw_properties().is_clipped,
contents_opaque, draw_properties().opacity,
@@ -307,6 +318,25 @@ void LayerImpl::SetScrollable(const gfx::Size& bounds) {
NoteLayerPropertyChanged();
}
+void LayerImpl::SetTouchActionRegion(TouchActionRegion region) {
+ // Avoid recalculating the cached |all_touch_action_regions_| value.
+ if (touch_action_region_ == region)
+ return;
+ touch_action_region_ = std::move(region);
+ all_touch_action_regions_ = nullptr;
+}
+
+const Region& LayerImpl::GetAllTouchActionRegions() const {
+ if (!all_touch_action_regions_) {
+ all_touch_action_regions_ =
+ std::make_unique<Region>(touch_action_region_.GetAllRegions());
+ } else {
+ // Ensure the cached value of |all_touch_action_regions_| is up to date.
+ DCHECK_EQ(touch_action_region_.GetAllRegions(), *all_touch_action_regions_);
+ }
+ return *all_touch_action_regions_;
+}
+
std::unique_ptr<LayerImpl> LayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
return LayerImpl::Create(tree_impl, layer_id_);
@@ -337,6 +367,10 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->hit_testable_ = hit_testable_;
layer->non_fast_scrollable_region_ = non_fast_scrollable_region_;
layer->touch_action_region_ = touch_action_region_;
+ layer->all_touch_action_regions_ =
+ all_touch_action_regions_
+ ? std::make_unique<Region>(*all_touch_action_regions_)
+ : nullptr;
layer->wheel_event_handler_region_ = wheel_event_handler_region_;
layer->background_color_ = background_color_;
layer->safe_opaque_background_color_ = safe_opaque_background_color_;
@@ -345,6 +379,7 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->clip_tree_index_ = clip_tree_index_;
layer->scroll_tree_index_ = scroll_tree_index_;
layer->has_will_change_transform_hint_ = has_will_change_transform_hint_;
+ layer->mirror_count_ = mirror_count_;
layer->scrollbars_hidden_ = scrollbars_hidden_;
if (needs_show_scrollbars_)
layer->needs_show_scrollbars_ = needs_show_scrollbars_;
@@ -435,9 +470,8 @@ std::unique_ptr<base::DictionaryValue> LayerImpl::LayerAsJson() const {
if (scrollable())
result->SetBoolean("Scrollable", true);
- if (!touch_action_region_.region().IsEmpty()) {
- std::unique_ptr<base::Value> region =
- touch_action_region_.region().AsValue();
+ if (!GetAllTouchActionRegions().IsEmpty()) {
+ std::unique_ptr<base::Value> region = GetAllTouchActionRegions().AsValue();
result->Set("TouchRegion", std::move(region));
}
@@ -516,7 +550,6 @@ void LayerImpl::ResetChangeTracking() {
needs_push_properties_ = false;
update_rect_.SetRect(0, 0, 0, 0);
- damage_rect_.SetRect(0, 0, 0, 0);
}
bool LayerImpl::IsActive() const {
@@ -696,12 +729,16 @@ void LayerImpl::SetElementId(ElementId element_id) {
layer_tree_impl_->AddToElementLayerList(element_id_, this);
}
+void LayerImpl::SetMirrorCount(int mirror_count) {
+ mirror_count_ = mirror_count;
+}
+
void LayerImpl::SetUpdateRect(const gfx::Rect& update_rect) {
update_rect_ = update_rect;
}
-void LayerImpl::AddDamageRect(const gfx::Rect& damage_rect) {
- damage_rect_.Union(damage_rect);
+gfx::Rect LayerImpl::GetDamageRect() const {
+ return gfx::Rect();
}
void LayerImpl::SetCurrentScrollOffset(const gfx::ScrollOffset& scroll_offset) {
@@ -802,9 +839,9 @@ void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const {
MathUtil::MapQuad(ScreenSpaceTransform(),
gfx::QuadF(gfx::RectF(gfx::Rect(bounds()))), &clipped);
MathUtil::AddToTracedValue("layer_quad", layer_quad, state);
- if (!touch_action_region_.region().IsEmpty()) {
- state->BeginArray("touch_action_region_region");
- touch_action_region_.region().AsValueInto(state);
+ if (!GetAllTouchActionRegions().IsEmpty()) {
+ state->BeginArray("all_touch_action_regions");
+ GetAllTouchActionRegions().AsValueInto(state);
state->EndArray();
}
if (!wheel_event_handler_region_.IsEmpty()) {
@@ -925,11 +962,6 @@ float LayerImpl::GetIdealContentsScale() const {
float device_scale = layer_tree_impl()->device_scale_factor();
float default_scale = page_scale * device_scale;
- if (!layer_tree_impl()
- ->settings()
- .layer_transforms_should_scale_layer_contents) {
- return default_scale;
- }
const auto& transform = ScreenSpaceTransform();
if (transform.HasPerspective()) {
diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h
index b98cfd6ad3c..be26a60ae36 100644
--- a/chromium/cc/layers/layer_impl.h
+++ b/chromium/cc/layers/layer_impl.h
@@ -30,8 +30,8 @@
#include "cc/layers/performance_properties.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/layers/touch_action_region.h"
+#include "cc/paint/element_id.h"
#include "cc/tiles/tile_priority.h"
-#include "cc/trees/element_id.h"
#include "cc/trees/target_property.h"
#include "components/viz/common/quads/shared_quad_state.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -129,13 +129,19 @@ class CC_EXPORT LayerImpl {
void PopulateSharedQuadState(viz::SharedQuadState* state,
bool contents_opaque) const;
- // If using this, you need to override GetEnclosingRectInTargetSpace() to
+ // If using these two, you need to override GetEnclosingRectInTargetSpace() to
// use GetScaledEnclosingRectInTargetSpace(). To do otherwise may result in
// inconsistent values, and drawing/clipping problems.
void PopulateScaledSharedQuadState(viz::SharedQuadState* state,
- float layer_to_content_scale_x,
- float layer_to_content_scale_y,
+ float layer_to_content_scale,
bool contents_opaque) const;
+ void PopulateScaledSharedQuadStateWithContentRects(
+ viz::SharedQuadState* state,
+ float layer_to_content_scale,
+ const gfx::Rect& content_rect,
+ const gfx::Rect& content_visible_rect,
+ bool contents_opaque) const;
+
// WillDraw must be called before AppendQuads. If WillDraw returns false,
// AppendQuads and DidDraw will not be called. If WillDraw returns true,
// DidDraw is guaranteed to be called before another WillDraw or before
@@ -194,6 +200,9 @@ class CC_EXPORT LayerImpl {
void SetElementId(ElementId element_id);
ElementId element_id() const { return element_id_; }
+ void SetMirrorCount(int mirror_count);
+ int mirror_count() const { return mirror_count_; }
+
bool IsAffectedByPageScale() const;
bool Is3dSorted() const { return GetSortingContextId() != 0; }
@@ -311,12 +320,14 @@ class CC_EXPORT LayerImpl {
return non_fast_scrollable_region_;
}
- void SetTouchActionRegion(TouchActionRegion touch_action_region) {
- touch_action_region_ = std::move(touch_action_region);
- }
+ void SetTouchActionRegion(TouchActionRegion);
const TouchActionRegion& touch_action_region() const {
return touch_action_region_;
}
+ const Region& GetAllTouchActionRegions() const;
+ bool has_touch_action_regions() const {
+ return !touch_action_region_.IsEmpty();
+ }
// Set or get the region that contains wheel event handler.
// The |wheel_event_handler_region| specify the area where wheel event handler
@@ -332,8 +343,10 @@ class CC_EXPORT LayerImpl {
void SetUpdateRect(const gfx::Rect& update_rect);
const gfx::Rect& update_rect() const { return update_rect_; }
- void AddDamageRect(const gfx::Rect& damage_rect);
- const gfx::Rect& damage_rect() const { return damage_rect_; }
+ // Denotes an area that is damaged and needs redraw. This is in the layer's
+ // space. By default returns empty rect, but can be overridden by subclasses
+ // as appropriate.
+ virtual gfx::Rect GetDamageRect() const;
virtual std::unique_ptr<base::DictionaryValue> LayerAsJson() const;
// TODO(pdr): This should be removed because there is no longer a tree
@@ -349,7 +362,7 @@ class CC_EXPORT LayerImpl {
// from property_trees changes in animaiton.
bool LayerPropertyChangedNotFromPropertyTrees() const;
- void ResetChangeTracking();
+ virtual void ResetChangeTracking();
virtual SimpleEnclosedRegion VisibleOpaqueRegion() const;
@@ -437,8 +450,6 @@ class CC_EXPORT LayerImpl {
// PopulateScaledSharedQuadStateQuadState() for more details.
gfx::Rect GetScaledEnclosingRectInTargetSpace(float scale) const;
- void UpdatePropertyTreeForAnimationIfNeeded(ElementId element_id);
-
float GetIdealContentsScale() const;
void NoteLayerPropertyChanged();
@@ -569,10 +580,6 @@ class CC_EXPORT LayerImpl {
// This is in the layer's space.
gfx::Rect update_rect_;
- // Denotes an area that is damaged and needs redraw. This is in the layer's
- // space.
- gfx::Rect damage_rect_;
-
// Group of properties that need to be computed based on the layer tree
// hierarchy before layers can be drawn.
DrawProperties draw_properties_;
@@ -581,6 +588,10 @@ class CC_EXPORT LayerImpl {
std::unique_ptr<base::trace_event::TracedValue> owned_debug_info_;
base::trace_event::TracedValue* debug_info_;
+ // Cache of all regions represented by any touch action from
+ // |touch_action_region_|.
+ mutable std::unique_ptr<Region> all_touch_action_regions_;
+
bool has_will_change_transform_hint_ : 1;
bool needs_push_properties_ : 1;
bool is_scrollbar_ : 1;
@@ -598,6 +609,10 @@ class CC_EXPORT LayerImpl {
bool raster_even_if_not_drawn_ : 1;
bool has_transform_node_ : 1;
+
+ // Number of layers mirroring this layer. If greater than zero, forces a
+ // render pass for the layer so it can be embedded by the mirroring layer.
+ int mirror_count_;
};
} // namespace cc
diff --git a/chromium/cc/layers/layer_impl_test_properties.h b/chromium/cc/layers/layer_impl_test_properties.h
index 0d2c134b2b4..b0818808729 100644
--- a/chromium/cc/layers/layer_impl_test_properties.h
+++ b/chromium/cc/layers/layer_impl_test_properties.h
@@ -50,6 +50,7 @@ struct CC_EXPORT LayerImplTestProperties {
FilterOperations filters;
FilterOperations backdrop_filters;
base::Optional<gfx::RRectF> backdrop_filter_bounds;
+ ElementId backdrop_mask_element_id;
float backdrop_filter_quality;
gfx::PointF filters_origin;
SkBlendMode blend_mode;
diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc
index 9200f7a7be1..4dc4d5b24af 100644
--- a/chromium/cc/layers/layer_impl_unittest.cc
+++ b/chromium/cc/layers/layer_impl_unittest.cc
@@ -391,7 +391,6 @@ TEST(LayerImplTest, PerspectiveTransformHasReasonableScale) {
std::unique_ptr<LayerTreeFrameSink> layer_tree_frame_sink =
FakeLayerTreeFrameSink::Create3d();
LayerTreeSettings settings;
- settings.layer_transforms_should_scale_layer_contents = true;
FakeLayerTreeHostImpl host_impl(settings, &task_runner_provider,
&task_graph_runner);
auto owned_layer = LayerImpl::Create(host_impl.active_tree(), 1);
@@ -604,6 +603,31 @@ TEST_F(LayerImplScrollTest, ScrollUserUnscrollableLayer) {
EXPECT_VECTOR_EQ(gfx::Vector2dF(30.5f, 5), layer()->CurrentScrollOffset());
}
+// |LayerImpl::all_touch_action_regions_| is a cache of all regions on
+// |LayerImpl::touch_action_region_| and must be invalidated on changes.
+TEST_F(LayerImplScrollTest, TouchActionRegionCacheInvalidation) {
+ host_impl().CreatePendingTree();
+ std::unique_ptr<LayerImpl> pending_layer =
+ LayerImpl::Create(host_impl().pending_tree(), 2);
+
+ TouchActionRegion region;
+ region.Union(kTouchActionNone, gfx::Rect(0, 0, 50, 50));
+ pending_layer->SetTouchActionRegion(region);
+
+ // The values for GetAllTouchActionRegions should be correct on both layers.
+ // Note that querying GetAllTouchActionRegions will update the cached value
+ // in |LayerImpl::all_touch_action_regions_|.
+ EXPECT_EQ(pending_layer->GetAllTouchActionRegions(), region.GetAllRegions());
+ EXPECT_EQ(layer()->GetAllTouchActionRegions(), Region());
+
+ pending_layer->PushPropertiesTo(layer());
+
+ // After pushing properties, the value for GetAllTouchActionRegions should
+ // not be stale.
+ EXPECT_EQ(pending_layer->GetAllTouchActionRegions(), region.GetAllRegions());
+ EXPECT_EQ(layer()->GetAllTouchActionRegions(), region.GetAllRegions());
+}
+
TEST_F(CommitToPendingTreeLayerImplScrollTest,
PushPropertiesToMirrorsCurrentScrollOffset) {
gfx::ScrollOffset scroll_offset(10, 5);
diff --git a/chromium/cc/layers/layer_sticky_position_constraint.h b/chromium/cc/layers/layer_sticky_position_constraint.h
index 8eedea825c7..d3075d95b74 100644
--- a/chromium/cc/layers/layer_sticky_position_constraint.h
+++ b/chromium/cc/layers/layer_sticky_position_constraint.h
@@ -7,7 +7,7 @@
#include "cc/cc_export.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -33,7 +33,7 @@ struct CC_EXPORT LayerStickyPositionConstraint {
// The rectangle in which the sticky box is able to be positioned. This may be
// smaller than the scroller viewport due to things like padding.
- gfx::RectF constraint_box_rect;
+ gfx::Rect constraint_box_rect;
// The rectangle corresponding to original layout position of the sticky box
// relative to the scroll ancestor. The sticky box is only offset once the
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index 0a02373e4d9..bd3b89aac8c 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -27,6 +27,7 @@
#include "cc/test/layer_test_common.h"
#include "cc/test/stub_layer_tree_host_single_thread_client.h"
#include "cc/test/test_task_graph_runner.h"
+#include "cc/trees/clip_node.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/transform_node.h"
@@ -59,14 +60,14 @@ using ::testing::_;
code_to_test; \
root->layer_tree_host()->BuildPropertyTreesForTesting(); \
EXPECT_TRUE(root->subtree_property_changed()); \
- EXPECT_TRUE(base::ContainsKey( \
+ EXPECT_TRUE(base::Contains( \
root->layer_tree_host()->LayersThatShouldPushProperties(), root.get())); \
EXPECT_TRUE(child->subtree_property_changed()); \
- EXPECT_TRUE(base::ContainsKey( \
+ EXPECT_TRUE(base::Contains( \
child->layer_tree_host()->LayersThatShouldPushProperties(), \
child.get())); \
EXPECT_TRUE(grand_child->subtree_property_changed()); \
- EXPECT_TRUE(base::ContainsKey( \
+ EXPECT_TRUE(base::Contains( \
grand_child->layer_tree_host()->LayersThatShouldPushProperties(), \
grand_child.get()));
@@ -74,14 +75,14 @@ using ::testing::_;
code_to_test; \
root->layer_tree_host()->BuildPropertyTreesForTesting(); \
EXPECT_FALSE(root->subtree_property_changed()); \
- EXPECT_FALSE(base::ContainsKey( \
+ EXPECT_FALSE(base::Contains( \
root->layer_tree_host()->LayersThatShouldPushProperties(), root.get())); \
EXPECT_FALSE(child->subtree_property_changed()); \
- EXPECT_FALSE(base::ContainsKey( \
+ EXPECT_FALSE(base::Contains( \
child->layer_tree_host()->LayersThatShouldPushProperties(), \
child.get())); \
EXPECT_FALSE(grand_child->subtree_property_changed()); \
- EXPECT_FALSE(base::ContainsKey( \
+ EXPECT_FALSE(base::Contains( \
grand_child->layer_tree_host()->LayersThatShouldPushProperties(), \
grand_child.get()));
@@ -350,15 +351,8 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
child2->PushPropertiesTo(child2_impl.get());
grand_child->PushPropertiesTo(grand_child_impl.get()));
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetRoundedCorner({1, 2, 3, 4}));
- EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
- root->PushPropertiesTo(root_impl.get());
- child->PushPropertiesTo(child_impl.get());
- child2->PushPropertiesTo(child2_impl.get());
- grand_child->PushPropertiesTo(grand_child_impl.get()));
-
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2);
+ root->SetRoundedCorner({1, 2, 3, 4});
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetIsFastRoundedCorner(true));
EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
root->PushPropertiesTo(root_impl.get());
@@ -367,14 +361,6 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
grand_child->PushPropertiesTo(grand_child_impl.get()));
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetRoundedCorner({0, 0, 0, 0}));
- EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
- root->PushPropertiesTo(root_impl.get());
- child->PushPropertiesTo(child_impl.get());
- child2->PushPropertiesTo(child2_impl.get());
- grand_child->PushPropertiesTo(grand_child_impl.get()));
-
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetDoubleSided(false));
EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
root->PushPropertiesTo(root_impl.get());
@@ -586,7 +572,7 @@ TEST_F(LayerTest, ReorderChildren) {
EXPECT_EQ(child2, parent->children()[2]);
for (const auto& child : parent->children()) {
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host_->LayersThatShouldPushProperties(), child.get()));
EXPECT_TRUE(child->subtree_property_changed());
}
@@ -758,8 +744,8 @@ TEST_F(LayerTest, DeleteRemovedScrollParent) {
SimulateCommitForLayer(child1.get());
EXPECT_SET_NEEDS_COMMIT(1, child1->SetScrollParent(nullptr));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host_->LayersThatShouldPushProperties(), child1.get()));
+ EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(),
+ child1.get()));
EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(nullptr));
}
@@ -1011,6 +997,7 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
1, test_layer->SetTransformOrigin(gfx::Point3F(1.23f, 4.56f, 0.f)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBackgroundColor(SK_ColorLTGRAY));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetMasksToBounds(true));
+ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetClipRect(gfx::Rect(1, 2, 3, 4)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetRoundedCorner({1, 2, 3, 4}));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsFastRoundedCorner(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f));
@@ -1654,6 +1641,298 @@ TEST_F(LayerTest, SetElementIdNotUsingLayerLists) {
test_layer->SetLayerTreeHost(nullptr);
}
+// Verifies that mirror count is pushed to the LayerImpl.
+TEST_F(LayerTest, MirrorCountIsPushed) {
+ scoped_refptr<Layer> test_layer = Layer::Create();
+ std::unique_ptr<LayerImpl> impl_layer =
+ LayerImpl::Create(host_impl_.active_tree(), 1);
+ test_layer->SetLayerTreeHost(layer_tree_host_.get());
+ EXPECT_EQ(0, test_layer->mirror_count());
+ EXPECT_EQ(0, impl_layer->mirror_count());
+
+ test_layer->IncrementMirrorCount();
+ EXPECT_EQ(1, test_layer->mirror_count());
+ EXPECT_EQ(0, impl_layer->mirror_count());
+
+ test_layer->PushPropertiesTo(impl_layer.get());
+ EXPECT_EQ(1, test_layer->mirror_count());
+ EXPECT_EQ(1, impl_layer->mirror_count());
+
+ test_layer->SetLayerTreeHost(nullptr);
+}
+
+// Verifies that when mirror count of the layer is incremented or decremented,
+// SetPropertyTreesNeedRebuild() and SetNeedsPushProperties() are called
+// appropriately.
+TEST_F(LayerTest, UpdateMirrorCount) {
+ scoped_refptr<Layer> test_layer = Layer::Create();
+ test_layer->SetLayerTreeHost(layer_tree_host_.get());
+ layer_tree_host_->property_trees()->needs_rebuild = false;
+ layer_tree_host_->ClearLayersThatShouldPushProperties();
+ EXPECT_EQ(0, test_layer->mirror_count());
+ EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild);
+ EXPECT_EQ(0u, layer_tree_host_->LayersThatShouldPushProperties().size());
+
+ // Incrementing mirror count from zero should trigger property trees rebuild.
+ test_layer->IncrementMirrorCount();
+ EXPECT_EQ(1, test_layer->mirror_count());
+ EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild);
+ EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(),
+ test_layer.get()));
+
+ layer_tree_host_->property_trees()->needs_rebuild = false;
+ layer_tree_host_->ClearLayersThatShouldPushProperties();
+
+ // Incrementing mirror count from non-zero should not trigger property trees
+ // rebuild.
+ test_layer->IncrementMirrorCount();
+ EXPECT_EQ(2, test_layer->mirror_count());
+ EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild);
+ EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(),
+ test_layer.get()));
+
+ layer_tree_host_->ClearLayersThatShouldPushProperties();
+
+ // Decrementing mirror count to non-zero should not trigger property trees
+ // rebuild.
+ test_layer->DecrementMirrorCount();
+ EXPECT_EQ(1, test_layer->mirror_count());
+ EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild);
+ EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(),
+ test_layer.get()));
+
+ layer_tree_host_->ClearLayersThatShouldPushProperties();
+
+ // Decrementing mirror count to zero should trigger property trees rebuild.
+ test_layer->DecrementMirrorCount();
+ EXPECT_EQ(0, test_layer->mirror_count());
+ EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild);
+ EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(),
+ test_layer.get()));
+
+ test_layer->SetLayerTreeHost(nullptr);
+}
+
+TEST_F(LayerTest, UpdatingClipRect) {
+ const gfx::Size kRootSize(200, 200);
+ const gfx::Vector2dF kParentOffset(10.f, 20.f);
+ const gfx::Size kLayerSize(100, 100);
+ const gfx::Rect kClipRect(50, 25, 100, 100);
+ const gfx::Rect kUpdatedClipRect_1(10, 20, 150, 200);
+ const gfx::Rect kUpdatedClipRect_2(20, 20, 50, 100);
+ const gfx::Rect kUpdatedClipRect_3(50, 25, 100, 80);
+ const gfx::Rect kUpdatedClipRect_4(10, 10, 200, 200);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> parent = Layer::Create();
+ scoped_refptr<Layer> clipped_1 = Layer::Create();
+ scoped_refptr<Layer> clipped_2 = Layer::Create();
+ scoped_refptr<Layer> clipped_3 = Layer::Create();
+ scoped_refptr<Layer> clipped_4 = Layer::Create();
+
+ EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1));
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
+ layer_tree_host_->SetRootLayer(root);
+ root->AddChild(parent);
+ parent->AddChild(clipped_1);
+ parent->AddChild(clipped_2);
+ parent->AddChild(clipped_3);
+ parent->AddChild(clipped_4);
+
+ root->SetBounds(kRootSize);
+ parent->SetBounds(kRootSize);
+ clipped_1->SetBounds(kLayerSize);
+ clipped_2->SetBounds(kLayerSize);
+ clipped_3->SetBounds(kLayerSize);
+ clipped_4->SetBounds(kLayerSize);
+
+ // This should introduce the |offset_from_transform_parent| component.
+ parent->SetPosition(gfx::PointF() + kParentOffset);
+
+ clipped_1->SetClipRect(kClipRect);
+ clipped_2->SetClipRect(kClipRect);
+ clipped_3->SetClipRect(kClipRect);
+ clipped_4->SetClipRect(kClipRect);
+ EXPECT_EQ(clipped_1->clip_rect(), kClipRect);
+ EXPECT_EQ(clipped_2->clip_rect(), kClipRect);
+ EXPECT_EQ(clipped_3->clip_rect(), kClipRect);
+ EXPECT_EQ(clipped_4->clip_rect(), kClipRect);
+
+ root->layer_tree_host()->BuildPropertyTreesForTesting();
+ ClipNode* node_1 = layer_tree_host_->property_trees()->clip_tree.Node(
+ clipped_1->clip_tree_index());
+ ClipNode* node_2 = layer_tree_host_->property_trees()->clip_tree.Node(
+ clipped_2->clip_tree_index());
+ ClipNode* node_3 = layer_tree_host_->property_trees()->clip_tree.Node(
+ clipped_3->clip_tree_index());
+ ClipNode* node_4 = layer_tree_host_->property_trees()->clip_tree.Node(
+ clipped_4->clip_tree_index());
+
+ EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_1->clip);
+ EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_2->clip);
+ EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_3->clip);
+ EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_4->clip);
+
+ // The following layer properties should result in the layer being clipped to
+ // its bounds along with being clipped by the clip rect. Check if the final
+ // rect on the clip node is set correctly.
+
+ // Setting clip to layer bounds.
+ clipped_1->SetMasksToBounds(true);
+
+ // Setting a mask.
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
+ clipped_2->SetMaskLayer(mask.get());
+
+ // Setting a filter that moves pixels.
+ FilterOperations move_pixel_filters;
+ move_pixel_filters.Append(
+ FilterOperation::CreateBlurFilter(2, SkBlurImageFilter::kClamp_TileMode));
+ ASSERT_TRUE(move_pixel_filters.HasFilterThatMovesPixels());
+ clipped_3->SetFilters(move_pixel_filters);
+
+ clipped_1->SetClipRect(kUpdatedClipRect_1);
+ clipped_2->SetClipRect(kUpdatedClipRect_2);
+ clipped_3->SetClipRect(kUpdatedClipRect_3);
+ clipped_4->SetClipRect(kUpdatedClipRect_4);
+
+ node_1 = layer_tree_host_->property_trees()->clip_tree.Node(
+ clipped_1->clip_tree_index());
+ node_2 = layer_tree_host_->property_trees()->clip_tree.Node(
+ clipped_2->clip_tree_index());
+ node_3 = layer_tree_host_->property_trees()->clip_tree.Node(
+ clipped_3->clip_tree_index());
+ node_4 = layer_tree_host_->property_trees()->clip_tree.Node(
+ clipped_4->clip_tree_index());
+
+ EXPECT_EQ(node_1->clip,
+ gfx::IntersectRects(gfx::RectF(kUpdatedClipRect_1),
+ gfx::RectF(gfx::SizeF(kLayerSize))) +
+ kParentOffset);
+ EXPECT_EQ(node_2->clip,
+ gfx::IntersectRects(gfx::RectF(kUpdatedClipRect_2),
+ gfx::RectF(gfx::SizeF(kLayerSize))) +
+ kParentOffset);
+ EXPECT_EQ(node_3->clip,
+ gfx::IntersectRects(gfx::RectF(kUpdatedClipRect_3),
+ gfx::RectF(gfx::SizeF(kLayerSize))) +
+ kParentOffset);
+ EXPECT_EQ(node_4->clip, gfx::RectF(kUpdatedClipRect_4) + kParentOffset);
+}
+
+TEST_F(LayerTest, UpdatingRoundedCorners) {
+ const gfx::Size kRootSize(200, 200);
+ const gfx::Size kLayerSize(100, 100);
+ const gfx::Rect kClipRect(50, 25, 100, 100);
+ const gfx::Rect kUpdatedClipRect(10, 20, 30, 40);
+ const gfx::RoundedCornersF kRoundedCorners(5);
+ const gfx::RoundedCornersF kUpdatedRoundedCorners(10);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> layer_1 = Layer::Create();
+ scoped_refptr<Layer> layer_2 = Layer::Create();
+ scoped_refptr<Layer> layer_3 = Layer::Create();
+ scoped_refptr<Layer> layer_4 = Layer::Create();
+ scoped_refptr<Layer> layer_5 = Layer::Create();
+
+ EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1));
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
+ layer_tree_host_->SetRootLayer(root);
+ root->AddChild(layer_1);
+ root->AddChild(layer_2);
+ root->AddChild(layer_3);
+ root->AddChild(layer_4);
+ root->AddChild(layer_5);
+
+ root->SetBounds(kRootSize);
+ layer_1->SetBounds(kLayerSize);
+ layer_2->SetBounds(kLayerSize);
+ layer_3->SetBounds(kLayerSize);
+ layer_4->SetBounds(kLayerSize);
+ layer_5->SetBounds(kLayerSize);
+
+ layer_1->SetClipRect(kClipRect);
+ layer_2->SetClipRect(kClipRect);
+ layer_3->SetClipRect(kClipRect);
+ layer_4->SetClipRect(kClipRect);
+ layer_1->SetRoundedCorner(kRoundedCorners);
+ layer_2->SetRoundedCorner(kRoundedCorners);
+ layer_3->SetRoundedCorner(kRoundedCorners);
+ layer_4->SetRoundedCorner(kRoundedCorners);
+ layer_5->SetRoundedCorner(kRoundedCorners);
+ EXPECT_EQ(layer_1->corner_radii(), kRoundedCorners);
+ EXPECT_EQ(layer_2->corner_radii(), kRoundedCorners);
+ EXPECT_EQ(layer_3->corner_radii(), kRoundedCorners);
+ EXPECT_EQ(layer_4->corner_radii(), kRoundedCorners);
+ EXPECT_EQ(layer_5->corner_radii(), kRoundedCorners);
+
+ root->layer_tree_host()->BuildPropertyTreesForTesting();
+ EffectNode* node_1 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_1->effect_tree_index());
+ EffectNode* node_2 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_2->effect_tree_index());
+ EffectNode* node_3 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_3->effect_tree_index());
+ EffectNode* node_4 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_4->effect_tree_index());
+ EffectNode* node_5 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_5->effect_tree_index());
+
+ EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners),
+ node_1->rounded_corner_bounds);
+ EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners),
+ node_2->rounded_corner_bounds);
+ EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners),
+ node_3->rounded_corner_bounds);
+ EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners),
+ node_4->rounded_corner_bounds);
+ EXPECT_EQ(gfx::RRectF(gfx::RectF(gfx::Rect(kLayerSize)), kRoundedCorners),
+ node_5->rounded_corner_bounds);
+
+ // Setting clip to layer bounds.
+ layer_1->SetMasksToBounds(true);
+
+ // Setting a mask.
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
+ layer_2->SetMaskLayer(mask.get());
+
+ layer_1->SetRoundedCorner(kUpdatedRoundedCorners);
+ layer_2->SetRoundedCorner(kUpdatedRoundedCorners);
+ layer_3->SetRoundedCorner(kUpdatedRoundedCorners);
+ // Updates the clip rect instead of rounded corners.
+ layer_4->SetClipRect(kUpdatedClipRect);
+ layer_5->SetRoundedCorner(kUpdatedRoundedCorners);
+
+ node_1 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_1->effect_tree_index());
+ node_2 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_2->effect_tree_index());
+ node_3 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_3->effect_tree_index());
+ node_4 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_4->effect_tree_index());
+ node_5 = layer_tree_host_->property_trees()->effect_tree.Node(
+ layer_5->effect_tree_index());
+
+ EXPECT_EQ(gfx::RRectF(gfx::RectF(gfx::IntersectRects(gfx::Rect(kLayerSize),
+ kClipRect)),
+ kUpdatedRoundedCorners),
+ node_1->rounded_corner_bounds);
+ EXPECT_EQ(gfx::RRectF(gfx::RectF(gfx::IntersectRects(gfx::Rect(kLayerSize),
+ kClipRect)),
+ kUpdatedRoundedCorners),
+ node_2->rounded_corner_bounds);
+ EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kUpdatedRoundedCorners),
+ node_3->rounded_corner_bounds);
+ EXPECT_EQ(gfx::RRectF(gfx::RectF(kUpdatedClipRect), kRoundedCorners),
+ node_4->rounded_corner_bounds);
+ EXPECT_EQ(
+ gfx::RRectF(gfx::RectF(gfx::Rect(kLayerSize)), kUpdatedRoundedCorners),
+ node_5->rounded_corner_bounds);
+}
+
class LayerTestWithLayerLists : public LayerTest {
protected:
void SetUp() override {
diff --git a/chromium/cc/layers/mirror_layer.cc b/chromium/cc/layers/mirror_layer.cc
new file mode 100644
index 00000000000..b89e300d2d6
--- /dev/null
+++ b/chromium/cc/layers/mirror_layer.cc
@@ -0,0 +1,49 @@
+// Copyright 2019 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/layers/mirror_layer.h"
+
+#include "cc/layers/mirror_layer_impl.h"
+
+namespace cc {
+
+std::unique_ptr<LayerImpl> MirrorLayer::CreateLayerImpl(
+ LayerTreeImpl* tree_impl) {
+ return MirrorLayerImpl::Create(tree_impl, id());
+}
+
+void MirrorLayer::PushPropertiesTo(LayerImpl* layer) {
+ Layer::PushPropertiesTo(layer);
+
+ auto* mirror_layer = static_cast<MirrorLayerImpl*>(layer);
+ mirror_layer->SetMirroredLayerId(mirrored_layer_->id());
+}
+
+void MirrorLayer::SetLayerTreeHost(LayerTreeHost* host) {
+#if DCHECK_IS_ON()
+ if (host && host != layer_tree_host()) {
+ for (auto* p = parent(); p; p = p->parent())
+ DCHECK_NE(p, mirrored_layer_.get());
+ }
+#endif
+
+ Layer::SetLayerTreeHost(host);
+}
+
+scoped_refptr<MirrorLayer> MirrorLayer::Create(
+ scoped_refptr<Layer> mirrored_layer) {
+ return base::WrapRefCounted(new MirrorLayer(std::move(mirrored_layer)));
+}
+
+MirrorLayer::MirrorLayer(scoped_refptr<Layer> mirrored_layer)
+ : mirrored_layer_(std::move(mirrored_layer)) {
+ DCHECK(mirrored_layer_);
+ mirrored_layer_->IncrementMirrorCount();
+}
+
+MirrorLayer::~MirrorLayer() {
+ mirrored_layer_->DecrementMirrorCount();
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/mirror_layer.h b/chromium/cc/layers/mirror_layer.h
new file mode 100644
index 00000000000..9915dcf525d
--- /dev/null
+++ b/chromium/cc/layers/mirror_layer.h
@@ -0,0 +1,42 @@
+// Copyright 2019 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.
+
+#ifndef CC_LAYERS_MIRROR_LAYER_H_
+#define CC_LAYERS_MIRROR_LAYER_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "cc/cc_export.h"
+#include "cc/layers/layer.h"
+
+namespace cc {
+
+// A layer that can mirror contents of another Layer.
+class CC_EXPORT MirrorLayer : public Layer {
+ public:
+ static scoped_refptr<MirrorLayer> Create(scoped_refptr<Layer> mirrored_layer);
+
+ MirrorLayer(const MirrorLayer&) = delete;
+ MirrorLayer& operator=(const MirrorLayer&) = delete;
+
+ Layer* mirrored_layer() const { return mirrored_layer_.get(); }
+
+ // Layer overrides.
+ std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
+ void PushPropertiesTo(LayerImpl* layer) override;
+ void SetLayerTreeHost(LayerTreeHost* host) override;
+
+ protected:
+ explicit MirrorLayer(scoped_refptr<Layer> mirrored_layer);
+
+ private:
+ ~MirrorLayer() override;
+
+ // A reference to a layer that is mirrored by this layer. |mirrored_layer_|
+ // cannot be an ancestor of |this|.
+ scoped_refptr<Layer> mirrored_layer_;
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_MIRROR_LAYER_H_
diff --git a/chromium/cc/layers/mirror_layer_impl.cc b/chromium/cc/layers/mirror_layer_impl.cc
new file mode 100644
index 00000000000..97099507d86
--- /dev/null
+++ b/chromium/cc/layers/mirror_layer_impl.cc
@@ -0,0 +1,92 @@
+// Copyright 2019 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/layers/mirror_layer_impl.h"
+
+#include "cc/layers/append_quads_data.h"
+#include "cc/trees/effect_node.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/occlusion.h"
+#include "components/viz/common/quads/render_pass_draw_quad.h"
+
+namespace cc {
+
+MirrorLayerImpl::MirrorLayerImpl(LayerTreeImpl* tree_impl, int id)
+ : LayerImpl(tree_impl, id) {}
+
+MirrorLayerImpl::~MirrorLayerImpl() = default;
+
+std::unique_ptr<LayerImpl> MirrorLayerImpl::CreateLayerImpl(
+ LayerTreeImpl* tree_impl) {
+ return MirrorLayerImpl::Create(tree_impl, id());
+}
+
+void MirrorLayerImpl::AppendQuads(viz::RenderPass* render_pass,
+ AppendQuadsData* append_quads_data) {
+ // TODO(mohsen): Currently, effects on the mirrored layer (e.g mask and
+ // opacity) are ignored. Consider applying them here.
+
+ auto* mirrored_layer = layer_tree_impl()->LayerById(mirrored_layer_id_);
+ auto* mirrored_render_surface =
+ GetEffectTree().GetRenderSurface(mirrored_layer->effect_tree_index());
+ gfx::Rect content_rect = mirrored_render_surface->content_rect();
+
+ gfx::Rect unoccluded_content_rect =
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ content_rect);
+ if (unoccluded_content_rect.IsEmpty())
+ return;
+
+ append_quads_data->mirror_rect = drawable_content_rect();
+
+ const bool contents_opaque = false;
+ viz::SharedQuadState* shared_quad_state =
+ render_pass->CreateAndAppendSharedQuadState();
+ PopulateScaledSharedQuadStateWithContentRects(
+ shared_quad_state, mirrored_layer->GetIdealContentsScale(), content_rect,
+ content_rect, contents_opaque);
+
+ AppendDebugBorderQuad(render_pass, content_rect, shared_quad_state,
+ append_quads_data);
+
+ viz::ResourceId mask_resource_id = 0;
+ gfx::RectF mask_uv_rect;
+ gfx::Size mask_texture_size;
+
+ auto* mirrored_effect_node = mirrored_render_surface->OwningEffectNode();
+ auto* quad = render_pass->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>();
+ quad->SetNew(shared_quad_state, content_rect, unoccluded_content_rect,
+ mirrored_layer_id_, mask_resource_id, mask_uv_rect,
+ mask_texture_size, /*mask_applies_to_backdrop=*/false,
+ mirrored_effect_node->surface_contents_scale,
+ mirrored_effect_node->filters_origin,
+ gfx::RectF(gfx::Rect(content_rect.size())),
+ !layer_tree_impl()->settings().enable_edge_anti_aliasing, 0.f);
+}
+
+void MirrorLayerImpl::PushPropertiesTo(LayerImpl* layer) {
+ LayerImpl::PushPropertiesTo(layer);
+
+ auto* mirror_layer = static_cast<MirrorLayerImpl*>(layer);
+ mirror_layer->SetMirroredLayerId(mirrored_layer_id_);
+}
+
+gfx::Rect MirrorLayerImpl::GetDamageRect() const {
+ // TOOD(mohsen): Currently, the whole layer is marked as damaged. We should
+ // only consider the damage from the mirrored layer.
+ return gfx::Rect(bounds());
+}
+
+gfx::Rect MirrorLayerImpl::GetEnclosingRectInTargetSpace() const {
+ const LayerImpl* mirrored_layer =
+ layer_tree_impl()->LayerById(mirrored_layer_id_);
+ return GetScaledEnclosingRectInTargetSpace(
+ mirrored_layer->GetIdealContentsScale());
+}
+
+const char* MirrorLayerImpl::LayerTypeAsString() const {
+ return "cc::MirrorLayerImpl";
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/mirror_layer_impl.h b/chromium/cc/layers/mirror_layer_impl.h
new file mode 100644
index 00000000000..b2e62041014
--- /dev/null
+++ b/chromium/cc/layers/mirror_layer_impl.h
@@ -0,0 +1,63 @@
+// Copyright 2019 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.
+
+#ifndef CC_LAYERS_MIRROR_LAYER_IMPL_H_
+#define CC_LAYERS_MIRROR_LAYER_IMPL_H_
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "cc/cc_export.h"
+#include "cc/layers/layer_impl.h"
+
+namespace cc {
+
+// This type of layer is used to mirror contents of another layer (specified by
+// |mirrored_layer_id_|) by forcing a render pass for the mirrored layer and
+// adding a RenderPassDrawQuad in the compositor frame for this layer referring
+// to that render pass. The mirroring layer should not be a descendant of the
+// mirrored layer (in terms of the effect tree). Due to ordering requirements
+// for render passes in the compositor frame, the render pass containing
+// mirroring layer should appear after the render pass created for the mirrored
+// layer. Currently, render passes are in reverse-draw order of the effect tree,
+// so we should be careful that this reverse-draw order does not conflict with
+// render pass ordering requirement mentioned above.
+// TODO(mohsen): If necessary, reorder render passes in compositor frame such
+// that the render pass containing mirroring layer appears after the render pass
+// created for the mirrored layer.
+class CC_EXPORT MirrorLayerImpl : public LayerImpl {
+ public:
+ static std::unique_ptr<MirrorLayerImpl> Create(LayerTreeImpl* tree_impl,
+ int id) {
+ return base::WrapUnique(new MirrorLayerImpl(tree_impl, id));
+ }
+
+ MirrorLayerImpl(const MirrorLayerImpl&) = delete;
+ MirrorLayerImpl& operator=(const MirrorLayerImpl&) = delete;
+
+ ~MirrorLayerImpl() override;
+
+ void SetMirroredLayerId(int id) { mirrored_layer_id_ = id; }
+ int mirrored_layer_id() const { return mirrored_layer_id_; }
+
+ // LayerImpl overrides.
+ std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
+ void AppendQuads(viz::RenderPass* render_pass,
+ AppendQuadsData* append_quads_data) override;
+ void PushPropertiesTo(LayerImpl* layer) override;
+ gfx::Rect GetDamageRect() const override;
+ gfx::Rect GetEnclosingRectInTargetSpace() const override;
+
+ protected:
+ MirrorLayerImpl(LayerTreeImpl* tree_impl, int id);
+
+ private:
+ const char* LayerTypeAsString() const override;
+
+ int mirrored_layer_id_ = 0;
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_MIRROR_LAYER_IMPL_H_
diff --git a/chromium/cc/layers/mirror_layer_unittest.cc b/chromium/cc/layers/mirror_layer_unittest.cc
new file mode 100644
index 00000000000..9630d80571d
--- /dev/null
+++ b/chromium/cc/layers/mirror_layer_unittest.cc
@@ -0,0 +1,141 @@
+// Copyright 2019 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 <memory>
+
+#include "cc/animation/animation_host.h"
+#include "cc/layers/mirror_layer.h"
+#include "cc/layers/mirror_layer_impl.h"
+#include "cc/test/fake_impl_task_runner_provider.h"
+#include "cc/test/fake_layer_tree_host.h"
+#include "cc/test/fake_layer_tree_host_client.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/test_task_graph_runner.h"
+#include "cc/trees/tree_synchronizer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class MirrorLayerTest : public testing::Test {
+ public:
+ MirrorLayerTest() : host_impl_(&task_runner_provider_, &task_graph_runner_) {}
+
+ // Synchronizes |layer_tree_host_| and |host_impl_| and pushes surface ids.
+ void SynchronizeTrees() {
+ TreeSynchronizer::PushLayerProperties(layer_tree_host_.get(),
+ host_impl_.pending_tree());
+ }
+
+ protected:
+ void SetUp() override {
+ animation_host_ = AnimationHost::CreateForTesting(ThreadInstance::MAIN);
+ layer_tree_host_ = FakeLayerTreeHost::Create(
+ &fake_client_, &task_graph_runner_, animation_host_.get());
+ layer_tree_host_->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f,
+ viz::LocalSurfaceIdAllocation());
+ host_impl_.CreatePendingTree();
+ }
+
+ void TearDown() override {
+ layer_tree_host_->SetRootLayer(nullptr);
+ layer_tree_host_ = nullptr;
+ }
+
+ FakeLayerTreeHostClient fake_client_;
+ FakeImplTaskRunnerProvider task_runner_provider_;
+ TestTaskGraphRunner task_graph_runner_;
+ std::unique_ptr<AnimationHost> animation_host_;
+ std::unique_ptr<FakeLayerTreeHost> layer_tree_host_;
+ FakeLayerTreeHostImpl host_impl_;
+};
+
+// This test verifies that MirrorLayer properties are pushed across to
+// MirrorLayerImpl.
+TEST_F(MirrorLayerTest, PushProperties) {
+ auto root = Layer::Create();
+ layer_tree_host_->SetRootLayer(root);
+
+ auto mirrored = Layer::Create();
+ root->AddChild(mirrored);
+ auto mirror = MirrorLayer::Create(mirrored);
+ root->AddChild(mirror);
+
+ EXPECT_EQ(1, mirrored->mirror_count());
+ EXPECT_EQ(mirrored.get(), mirror->mirrored_layer());
+
+ auto root_impl = LayerImpl::Create(host_impl_.pending_tree(), root->id());
+ auto mirrored_impl =
+ LayerImpl::Create(host_impl_.pending_tree(), mirrored->id());
+ auto mirror_impl =
+ MirrorLayerImpl::Create(host_impl_.pending_tree(), mirror->id());
+
+ // Verify that impl layers have default property values.
+ EXPECT_EQ(0, mirrored_impl->mirror_count());
+ EXPECT_EQ(0, mirror_impl->mirrored_layer_id());
+
+ SynchronizeTrees();
+
+ // Verify that property values are pushed to impl layers.
+ EXPECT_EQ(1, mirrored_impl->mirror_count());
+ EXPECT_EQ(mirrored_impl->id(), mirror_impl->mirrored_layer_id());
+}
+
+// This test verifies adding/removing mirror layers updates mirror count
+// properly and sets appropriate bits on the layer tree host.
+TEST_F(MirrorLayerTest, MirrorCount) {
+ auto mirrored = Layer::Create();
+ mirrored->SetLayerTreeHost(layer_tree_host_.get());
+
+ layer_tree_host_->property_trees()->needs_rebuild = false;
+ layer_tree_host_->ClearLayersThatShouldPushProperties();
+ EXPECT_EQ(0, mirrored->mirror_count());
+
+ // Creating the first mirror layer should trigger property trees rebuild.
+ auto mirror1 = MirrorLayer::Create(mirrored);
+ EXPECT_EQ(1, mirrored->mirror_count());
+ EXPECT_EQ(mirrored.get(), mirror1->mirrored_layer());
+ EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild);
+ EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(),
+ mirrored.get()));
+
+ layer_tree_host_->property_trees()->needs_rebuild = false;
+ layer_tree_host_->ClearLayersThatShouldPushProperties();
+
+ // Creating a second mirror layer should not trigger property trees rebuild.
+ auto mirror2 = MirrorLayer::Create(mirrored);
+ EXPECT_EQ(2, mirrored->mirror_count());
+ EXPECT_EQ(mirrored.get(), mirror2->mirrored_layer());
+ EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild);
+ EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(),
+ mirrored.get()));
+
+ layer_tree_host_->property_trees()->needs_rebuild = false;
+ layer_tree_host_->ClearLayersThatShouldPushProperties();
+
+ // Destroying one of the mirror layers should not trigger property trees
+ // rebuild.
+ mirror1->RemoveFromParent();
+ mirror1 = nullptr;
+ EXPECT_EQ(1, mirrored->mirror_count());
+ EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild);
+ EXPECT_EQ(1u, layer_tree_host_->LayersThatShouldPushProperties().size());
+
+ layer_tree_host_->property_trees()->needs_rebuild = false;
+ layer_tree_host_->ClearLayersThatShouldPushProperties();
+
+ // Destroying the only remaining mirror layer should trigger property trees
+ // rebuild.
+ mirror2->RemoveFromParent();
+ mirror2 = nullptr;
+ EXPECT_EQ(0, mirrored->mirror_count());
+ EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild);
+ EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(),
+ mirrored.get()));
+
+ mirrored->SetLayerTreeHost(nullptr);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/nine_patch_generator.cc b/chromium/cc/layers/nine_patch_generator.cc
index 7677f48bd11..30214034a44 100644
--- a/chromium/cc/layers/nine_patch_generator.cc
+++ b/chromium/cc/layers/nine_patch_generator.cc
@@ -362,7 +362,7 @@ void NinePatchGenerator::AppendQuads(LayerImpl* layer_impl,
image_rect.bottom_right(), SK_ColorTRANSPARENT,
vertex_opacity, flipped, nearest_neighbor_,
/*secure_output_only=*/false,
- ui::ProtectedVideoType::kClear);
+ gfx::ProtectedVideoType::kClear);
layer_impl->ValidateQuadResources(quad);
}
}
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
index c7e055e541d..3a865b28741 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
@@ -162,7 +162,7 @@ void PaintedOverlayScrollbarLayerImpl::AppendTrackQuads(
shared_quad_state, scaled_track_quad_rect, scaled_visible_track_quad_rect,
needs_blending, track_resource_id, premultipled_alpha, uv_top_left,
uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped, nearest_neighbor,
- /*secure_output_only=*/false, ui::ProtectedVideoType::kClear);
+ /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
ValidateQuadResources(quad);
}
diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc
index deda561b810..83df997f2b0 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer.cc
@@ -148,18 +148,14 @@ void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() {
}
void PaintedScrollbarLayer::UpdateInternalContentScale() {
- float scale = layer_tree_host()->device_scale_factor();
- if (layer_tree_host()
- ->GetSettings()
- .layer_transforms_should_scale_layer_contents) {
- gfx::Transform transform;
- transform = draw_property_utils::ScreenSpaceTransform(
- this, layer_tree_host()->property_trees()->transform_tree);
-
- gfx::Vector2dF transform_scales =
- MathUtil::ComputeTransform2dScaleComponents(transform, scale);
- scale = std::max(transform_scales.x(), transform_scales.y());
- }
+ gfx::Transform transform;
+ transform = draw_property_utils::ScreenSpaceTransform(
+ this, layer_tree_host()->property_trees()->transform_tree);
+
+ gfx::Vector2dF transform_scales = MathUtil::ComputeTransform2dScaleComponents(
+ transform, layer_tree_host()->device_scale_factor());
+ float scale = std::max(transform_scales.x(), transform_scales.y());
+
bool changed = false;
changed |= UpdateProperty(scale, &internal_contents_scale_);
changed |=
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
index 0788e665719..c6426b6c4f8 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
@@ -100,7 +100,7 @@ void PaintedScrollbarLayerImpl::AppendQuads(
viz::SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
PopulateScaledSharedQuadState(shared_quad_state, internal_contents_scale_,
- internal_contents_scale_, contents_opaque());
+ contents_opaque());
AppendDebugBorderQuad(render_pass, gfx::Rect(internal_content_bounds_),
shared_quad_state, append_quads_data);
@@ -129,7 +129,7 @@ void PaintedScrollbarLayerImpl::AppendQuads(
thumb_resource_id, premultipled_alpha, uv_top_left,
uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped,
nearest_neighbor, /*secure_output_only=*/false,
- ui::ProtectedVideoType::kClear);
+ gfx::ProtectedVideoType::kClear);
ValidateQuadResources(quad);
}
@@ -149,7 +149,7 @@ void PaintedScrollbarLayerImpl::AppendQuads(
track_resource_id, premultipled_alpha, uv_top_left,
uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped,
nearest_neighbor, /*secure_output_only=*/false,
- ui::ProtectedVideoType::kClear);
+ gfx::ProtectedVideoType::kClear);
ValidateQuadResources(quad);
}
}
diff --git a/chromium/cc/layers/painted_scrollbar_layer_unittest.cc b/chromium/cc/layers/painted_scrollbar_layer_unittest.cc
index 53ce3fabcef..bea0320631f 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_unittest.cc
@@ -9,6 +9,7 @@
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_scrollbar.h"
#include "cc/test/test_task_graph_runner.h"
+#include "cc/trees/layer_tree_host_common.h"
#include "testing/gmock/include/gmock/gmock.h"
using ::testing::Mock;
@@ -43,6 +44,11 @@ TEST(PaintedScrollbarLayerTest, NeedsPaint) {
scrollbar_layer->SetBounds(gfx::Size(100, 100));
layer_tree_host->SetRootLayer(scrollbar_layer);
+
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ scrollbar_layer.get(), scrollbar_layer->bounds());
+ LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
+
EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host.get());
// Request no paint, but expect them to be painted because they have not
diff --git a/chromium/cc/layers/picture_layer.cc b/chromium/cc/layers/picture_layer.cc
index 5447882cf61..049f7382668 100644
--- a/chromium/cc/layers/picture_layer.cc
+++ b/chromium/cc/layers/picture_layer.cc
@@ -82,7 +82,7 @@ void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
}
layer_impl->UpdateRasterSource(recording_source_->CreateRasterSource(),
- &last_updated_invalidation_, nullptr);
+ &last_updated_invalidation_, nullptr, nullptr);
DCHECK(last_updated_invalidation_.IsEmpty());
}
@@ -92,10 +92,6 @@ void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
if (!host)
return;
- if (!host->GetSettings().enable_mask_tiling &&
- mask_type_ == LayerMaskType::MULTI_TEXTURE_MASK)
- mask_type_ = LayerMaskType::SINGLE_TEXTURE_MASK;
-
if (!recording_source_)
recording_source_.reset(new RecordingSource);
recording_source_->SetSlowdownRasterScaleFactor(
@@ -165,11 +161,6 @@ bool PictureLayer::Update() {
}
void PictureLayer::SetLayerMaskType(LayerMaskType mask_type) {
- // We do not allow converting SINGLE_TEXTURE_MASK to MULTI_TEXTURE_MASK in
- // order to avoid rerastering when a mask's transform is being animated.
- if (mask_type_ == LayerMaskType::SINGLE_TEXTURE_MASK &&
- mask_type == LayerMaskType::MULTI_TEXTURE_MASK)
- return;
mask_type_ = mask_type;
}
@@ -249,7 +240,7 @@ void PictureLayer::RunMicroBenchmark(MicroBenchmark* benchmark) {
}
void PictureLayer::CaptureContent(const gfx::Rect& rect,
- std::vector<NodeHolder>* content) {
+ std::vector<NodeId>* content) {
if (!DrawsContent())
return;
diff --git a/chromium/cc/layers/picture_layer.h b/chromium/cc/layers/picture_layer.h
index 48ea87225a1..097782aa4cf 100644
--- a/chromium/cc/layers/picture_layer.h
+++ b/chromium/cc/layers/picture_layer.h
@@ -48,7 +48,7 @@ class CC_EXPORT PictureLayer : public Layer {
bool HasNonAAPaint() const override;
void RunMicroBenchmark(MicroBenchmark* benchmark) override;
void CaptureContent(const gfx::Rect& rect,
- std::vector<NodeHolder>* content) override;
+ std::vector<NodeId>* content) override;
ContentLayerClient* client() { return picture_layer_inputs_.client; }
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index b9cbcd3241a..23c71d964ec 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -48,23 +48,6 @@ const float kMaxScaleRatioDuringPinch = 2.0f;
// tiling's scale if the desired scale is within this ratio.
const float kSnapToExistingTilingRatio = 1.2f;
-// Even for really wide viewports, at some point GPU raster should use
-// less than 4 tiles to fill the viewport. This is set to 256 as a
-// sane minimum for now, but we might want to tune this for low-end.
-const int kMinHeightForGpuRasteredTile = 256;
-
-// When making odd-sized tiles, round them up to increase the chances
-// of using the same tile size.
-const int kTileRoundUp = 64;
-
-// Round GPU default tile sizes to a multiple of 32. This helps prevent
-// rounding errors during compositing.
-const int kGpuDefaultTileRoundUp = 32;
-
-// For performance reasons and to support compressed tile textures, tile
-// width and height should be an even multiple of 4 in size.
-const int kTileMinimalAlignment = 4;
-
// Large contents scale can cause overflow issues. Cap the ideal contents scale
// by this constant, since scales larger than this are usually not correct or
// their scale doesn't matter as long as it's large. Content scales usually
@@ -92,55 +75,6 @@ gfx::Rect SafeIntersectRects(const gfx::Rect& one, const gfx::Rect& two) {
static_cast<int>(rb - ry));
}
-// This function converts the given |device_pixels_size| to the expected size
-// of content which was generated to fill it at 100%. This takes into account
-// the ceil operations that occur as device pixels are converted to/from DIPs
-// (content size must be a whole number of DIPs).
-gfx::Size ApplyDsfAdjustment(gfx::Size device_pixels_size, float dsf) {
- gfx::Size content_size_in_dips =
- gfx::ScaleToCeiledSize(device_pixels_size, 1.0f / dsf);
- gfx::Size content_size_in_dps =
- gfx::ScaleToCeiledSize(content_size_in_dips, dsf);
- return content_size_in_dps;
-}
-
-// For GPU rasterization, we pick an ideal tile size using the viewport so we
-// don't need any settings. The current approach uses 4 tiles to cover the
-// viewport vertically.
-gfx::Size CalculateGpuTileSize(const gfx::Size& base_tile_size,
- const gfx::Size& content_bounds,
- const gfx::Size& max_tile_size) {
- int tile_width = base_tile_size.width();
-
- // Increase the height proportionally as the width decreases, and pad by our
- // border texels to make the tiles exactly match the viewport.
- int divisor = 4;
- if (content_bounds.width() <= base_tile_size.width() / 2)
- divisor = 2;
- if (content_bounds.width() <= base_tile_size.width() / 4)
- divisor = 1;
- int tile_height =
- MathUtil::UncheckedRoundUp(base_tile_size.height(), divisor) / divisor;
-
- // Grow default sizes to account for overlapping border texels.
- tile_width += 2 * PictureLayerTiling::kBorderTexels;
- tile_height += 2 * PictureLayerTiling::kBorderTexels;
-
- // Round GPU default tile sizes to a multiple of kGpuDefaultTileAlignment.
- // This helps prevent rounding errors in our CA path. https://crbug.com/632274
- tile_width = MathUtil::UncheckedRoundUp(tile_width, kGpuDefaultTileRoundUp);
- tile_height = MathUtil::UncheckedRoundUp(tile_height, kGpuDefaultTileRoundUp);
-
- tile_height = std::max(tile_height, kMinHeightForGpuRasteredTile);
-
- if (!max_tile_size.IsEmpty()) {
- tile_width = std::min(tile_width, max_tile_size.width());
- tile_height = std::min(tile_height, max_tile_size.height());
- }
-
- return gfx::Size(tile_width, tile_height);
-}
-
} // namespace
PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl,
@@ -164,13 +98,19 @@ PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl,
nearest_neighbor_(false),
use_transformed_rasterization_(false),
is_directly_composited_image_(false),
- can_use_lcd_text_(true) {
+ can_use_lcd_text_(true),
+ tile_size_calculator_(this) {
layer_tree_impl()->RegisterPictureLayerImpl(this);
}
PictureLayerImpl::~PictureLayerImpl() {
if (twin_layer_)
twin_layer_->twin_layer_ = nullptr;
+ // We only track PaintWorklet-containing PictureLayerImpls on the pending
+ // tree. However this deletion may happen outside the commit flow when we are
+ // on the recycle tree instead, so just check !IsActiveTree().
+ if (!paint_worklet_records_.empty() && !layer_tree_impl()->IsActiveTree())
+ layer_tree_impl()->NotifyLayerHasPaintWorkletsChanged(this, false);
layer_tree_impl()->UnregisterPictureLayerImpl(this);
// Unregister for all images on the current raster source.
@@ -223,8 +163,8 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
layer_tree_impl()->create_low_res_tiling() ? 2u : 1u);
layer_impl->set_gpu_raster_max_texture_size(gpu_raster_max_texture_size_);
- layer_impl->UpdateRasterSource(raster_source_, &invalidation_,
- tilings_.get());
+ layer_impl->UpdateRasterSource(raster_source_, &invalidation_, tilings_.get(),
+ &paint_worklet_records_);
DCHECK(invalidation_.IsEmpty());
// After syncing a solid color layer, the active layer has no tilings.
@@ -258,23 +198,19 @@ void PictureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
render_pass->CreateAndAppendSharedQuadState();
if (raster_source_->IsSolidColor()) {
- // TODO(sunxd): Solid color non-mask layers are forced to have contents
- // scale = 1. This is a workaround to temperarily fix
- // https://crbug.com/796558.
- // We need to investigate into the ca layers logic and remove this
- // workaround after fixing the bug.
- float max_contents_scale =
- !(mask_type_ == Layer::LayerMaskType::MULTI_TEXTURE_MASK)
- ? 1
- : CanHaveTilings() ? ideal_contents_scale_
- : std::min(kMaxIdealContentsScale,
- std::max(GetIdealContentsScale(),
- MinimumContentsScale()));
+ // TODO(979672): This is still hard-coded at 1.0. This has some history:
+ // - for crbug.com/769319, the contents scale was allowed to change, to
+ // avoid blurring on high-dpi screens.
+ // - for crbug.com/796558, the max device scale was hard-coded back to 1.0
+ // for single-tile masks, to avoid problems with transforms.
+ // To avoid those transform/scale bugs, this is currently left at 1.0. See
+ // crbug.com/979672 for more context and test links.
+ float max_contents_scale = 1;
// The downstream CA layers use shared_quad_state to generate resources of
// the right size even if it is a solid color picture layer.
PopulateScaledSharedQuadState(shared_quad_state, max_contents_scale,
- max_contents_scale, contents_opaque());
+ contents_opaque());
AppendDebugBorderQuad(render_pass, gfx::Rect(bounds()), shared_quad_state,
append_quads_data);
@@ -297,9 +233,13 @@ void PictureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
}
float device_scale_factor = layer_tree_impl()->device_scale_factor();
- float max_contents_scale = MaximumTilingContentsScale();
+ // If we don't have tilings, we're likely going to append a checkerboard quad
+ // the size of the layer. In that case, use scale 1 for more stable
+ // to-screen-space mapping.
+ float max_contents_scale =
+ tilings_->num_tilings() ? MaximumTilingContentsScale() : 1.f;
PopulateScaledSharedQuadState(shared_quad_state, max_contents_scale,
- max_contents_scale, contents_opaque());
+ contents_opaque());
Occlusion scaled_occlusion;
if (mask_type_ == Layer::LayerMaskType::NOT_MASK) {
scaled_occlusion =
@@ -495,7 +435,7 @@ void PictureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
float alpha =
(SkColorGetA(draw_info.solid_color()) * (1.0f / 255.0f)) *
shared_quad_state->opacity;
- if (mask_type_ == Layer::LayerMaskType::MULTI_TEXTURE_MASK ||
+ if (mask_type_ != Layer::LayerMaskType::NOT_MASK ||
alpha >= std::numeric_limits<float>::epsilon()) {
auto* quad =
render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
@@ -731,7 +671,8 @@ PictureLayerImpl* PictureLayerImpl::GetPendingOrActiveTwinLayer() const {
void PictureLayerImpl::UpdateRasterSource(
scoped_refptr<RasterSource> raster_source,
Region* new_invalidation,
- const PictureLayerTilingSet* pending_set) {
+ const PictureLayerTilingSet* pending_set,
+ const PaintWorkletRecordMap* pending_paint_worklet_records) {
// The bounds and the pile size may differ if the pile wasn't updated (ie.
// PictureLayer::Update didn't happen). In that case the pile will be empty.
DCHECK(raster_source->GetSize().IsEmpty() ||
@@ -747,9 +688,16 @@ void PictureLayerImpl::UpdateRasterSource(
// Unregister for all images on the current raster source, if the recording
// was updated.
- if (recording_updated)
+ if (recording_updated) {
UnregisterAnimatedImages();
+ // When the display list changes, the set of PaintWorklets may also change.
+ if (pending_paint_worklet_records)
+ paint_worklet_records_ = *pending_paint_worklet_records;
+ else
+ SetPaintWorkletInputs(raster_source->GetPaintWorkletInputs());
+ }
+
// The |raster_source_| is initially null, so have to check for that for the
// first frame.
bool could_have_tilings = raster_source_.get() && CanHaveTilings();
@@ -821,7 +769,7 @@ bool PictureLayerImpl::UpdateCanUseLCDTextAfterCommit() {
void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
if (layer_tree_impl()->IsActiveTree())
- AddDamageRect(tile->enclosing_layer_rect());
+ damage_rect_.Union(tile->enclosing_layer_rect());
if (tile->draw_info().NeedsRaster()) {
PictureLayerTiling* tiling =
tilings_->FindTilingWithScaleKey(tile->contents_scale_key());
@@ -830,6 +778,15 @@ void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
}
}
+gfx::Rect PictureLayerImpl::GetDamageRect() const {
+ return damage_rect_;
+}
+
+void PictureLayerImpl::ResetChangeTracking() {
+ LayerImpl::ResetChangeTracking();
+ damage_rect_.SetRect(0, 0, 0, 0);
+}
+
void PictureLayerImpl::DidBeginTracing() {
raster_source_->DidBeginTracing();
}
@@ -907,6 +864,10 @@ bool PictureLayerImpl::RequiresHighResToDraw() const {
return layer_tree_impl()->RequiresHighResToDraw();
}
+const PaintWorkletRecordMap& PictureLayerImpl::GetPaintWorkletRecords() const {
+ return paint_worklet_records_;
+}
+
gfx::Rect PictureLayerImpl::GetEnclosingRectInTargetSpace() const {
return GetScaledEnclosingRectInTargetSpace(MaximumTilingContentsScale());
}
@@ -944,90 +905,9 @@ bool PictureLayerImpl::ShouldAnimate(PaintImage::Id paint_image_id) const {
return false;
}
-gfx::Size PictureLayerImpl::CalculateTileSize(
- const gfx::Size& content_bounds) const {
- int max_texture_size = layer_tree_impl()->max_texture_size();
-
- if (mask_type_ == Layer::LayerMaskType::SINGLE_TEXTURE_MASK) {
- // Masks are not tiled, so if we can't cover the whole mask with one tile,
- // we shouldn't have such a tiling at all.
- DCHECK_LE(content_bounds.width(), max_texture_size);
- DCHECK_LE(content_bounds.height(), max_texture_size);
- return content_bounds;
- }
-
- int default_tile_width = 0;
- int default_tile_height = 0;
- if (layer_tree_impl()->use_gpu_rasterization()) {
- gfx::Size max_tile_size =
- layer_tree_impl()->settings().max_gpu_raster_tile_size;
-
- // Calculate |base_tile_size based| on |gpu_raster_max_texture_size_|,
- // adjusting for ceil operations that may occur due to DSF.
- gfx::Size base_tile_size = ApplyDsfAdjustment(
- gpu_raster_max_texture_size_, layer_tree_impl()->device_scale_factor());
-
- // Set our initial size assuming a |base_tile_size| equal to our
- // |viewport_size|.
- gfx::Size default_tile_size =
- CalculateGpuTileSize(base_tile_size, content_bounds, max_tile_size);
-
- // Use half-width GPU tiles when the content_width is greater than our
- // calculated tile size.
- if (content_bounds.width() > default_tile_size.width()) {
- // Divide width by 2 and round up.
- base_tile_size.set_width((base_tile_size.width() + 1) / 2);
- default_tile_size =
- CalculateGpuTileSize(base_tile_size, content_bounds, max_tile_size);
- }
-
- default_tile_width = default_tile_size.width();
- default_tile_height = default_tile_size.height();
- } else {
- // For CPU rasterization we use tile-size settings.
- const LayerTreeSettings& settings = layer_tree_impl()->settings();
- int max_untiled_content_width = settings.max_untiled_layer_size.width();
- int max_untiled_content_height = settings.max_untiled_layer_size.height();
- default_tile_width = settings.default_tile_size.width();
- default_tile_height = settings.default_tile_size.height();
-
- // If the content width is small, increase tile size vertically.
- // If the content height is small, increase tile size horizontally.
- // If both are less than the untiled-size, use a single tile.
- if (content_bounds.width() < default_tile_width)
- default_tile_height = max_untiled_content_height;
- if (content_bounds.height() < default_tile_height)
- default_tile_width = max_untiled_content_width;
- if (content_bounds.width() < max_untiled_content_width &&
- content_bounds.height() < max_untiled_content_height) {
- default_tile_height = max_untiled_content_height;
- default_tile_width = max_untiled_content_width;
- }
- }
-
- int tile_width = default_tile_width;
- int tile_height = default_tile_height;
-
- // Clamp the tile width/height to the content width/height to save space.
- if (content_bounds.width() < default_tile_width) {
- tile_width = std::min(tile_width, content_bounds.width());
- tile_width = MathUtil::UncheckedRoundUp(tile_width, kTileRoundUp);
- tile_width = std::min(tile_width, default_tile_width);
- }
- if (content_bounds.height() < default_tile_height) {
- tile_height = std::min(tile_height, content_bounds.height());
- tile_height = MathUtil::UncheckedRoundUp(tile_height, kTileRoundUp);
- tile_height = std::min(tile_height, default_tile_height);
- }
-
- // Ensure that tile width and height are properly aligned.
- tile_width = MathUtil::UncheckedRoundUp(tile_width, kTileMinimalAlignment);
- tile_height = MathUtil::UncheckedRoundUp(tile_height, kTileMinimalAlignment);
-
- // Under no circumstance should we be larger than the max texture size.
- tile_width = std::min(tile_width, max_texture_size);
- tile_height = std::min(tile_height, max_texture_size);
- return gfx::Size(tile_width, tile_height);
+gfx::Size PictureLayerImpl::CalculateTileSize(const gfx::Size& content_bounds) {
+ content_bounds_ = content_bounds;
+ return tile_size_calculator_.CalculateTileSize();
}
void PictureLayerImpl::GetContentsResourceId(
@@ -1470,6 +1350,8 @@ float PictureLayerImpl::MinimumContentsScale() const {
}
float PictureLayerImpl::MaximumContentsScale() const {
+ if (bounds().IsEmpty())
+ return 0;
// When mask tiling is disabled or the mask is single textured, masks can not
// have tilings that would become larger than the max_texture_size since they
// use a single tile for the entire tiling. Other layers can have tilings such
@@ -1478,9 +1360,8 @@ float PictureLayerImpl::MaximumContentsScale() const {
static_cast<float>(mask_type_ == Layer::LayerMaskType::SINGLE_TEXTURE_MASK
? layer_tree_impl()->max_texture_size()
: std::numeric_limits<int>::max());
- float max_scale_width = max_dimension / bounds().width();
- float max_scale_height = max_dimension / bounds().height();
- float max_scale = std::min(max_scale_width, max_scale_height);
+ int higher_dimension = std::max(bounds().width(), bounds().height());
+ float max_scale = max_dimension / higher_dimension;
// We require that multiplying the layer size by the contents scale and
// ceiling produces a value <= |max_dimension|. Because for large layer
@@ -1721,6 +1602,13 @@ PictureLayerImpl::InvalidateRegionForImages(
return ImageInvalidationResult::kInvalidated;
}
+void PictureLayerImpl::SetPaintWorkletRecord(
+ scoped_refptr<PaintWorkletInput> input,
+ sk_sp<PaintRecord> record) {
+ DCHECK(paint_worklet_records_.find(input) != paint_worklet_records_.end());
+ paint_worklet_records_[input] = std::move(record);
+}
+
void PictureLayerImpl::RegisterAnimatedImages() {
if (!raster_source_ || !raster_source_->GetDisplayItemList())
return;
@@ -1749,4 +1637,45 @@ void PictureLayerImpl::UnregisterAnimatedImages() {
controller->UnregisterAnimationDriver(data.paint_image_id, this);
}
+void PictureLayerImpl::SetPaintWorkletInputs(
+ const std::vector<scoped_refptr<PaintWorkletInput>>& inputs) {
+ bool had_paint_worklets = !paint_worklet_records_.empty();
+ PaintWorkletRecordMap new_records;
+ for (const auto& input : inputs) {
+ // Attempt to re-use an existing PaintRecord if possible.
+ new_records[input] = std::move(paint_worklet_records_[input]);
+ }
+ paint_worklet_records_.swap(new_records);
+
+ // The pending tree tracks which PictureLayerImpls have PaintWorkletInputs as
+ // an optimization to avoid walking all picture layers.
+ bool has_paint_worklets = !paint_worklet_records_.empty();
+ if ((has_paint_worklets != had_paint_worklets) &&
+ layer_tree_impl()->IsPendingTree()) {
+ layer_tree_impl()->NotifyLayerHasPaintWorkletsChanged(this,
+ has_paint_worklets);
+ }
+}
+
+std::unique_ptr<base::DictionaryValue> PictureLayerImpl::LayerAsJson() const {
+ auto result = LayerImpl::LayerAsJson();
+ auto dictionary = std::make_unique<base::DictionaryValue>();
+ if (raster_source_) {
+ dictionary->SetBoolean("IsSolidColor", raster_source_->IsSolidColor());
+ auto list = std::make_unique<base::ListValue>();
+ list->AppendInteger(raster_source_->GetSize().width());
+ list->AppendInteger(raster_source_->GetSize().height());
+ dictionary->Set("Size", std::move(list));
+ dictionary->SetBoolean("HasRecordings", raster_source_->HasRecordings());
+
+ const auto& display_list = raster_source_->GetDisplayItemList();
+ size_t op_count = display_list ? display_list->TotalOpCount() : 0;
+ size_t bytes_used = display_list ? display_list->BytesUsed() : 0;
+ dictionary->SetInteger("OpCount", op_count);
+ dictionary->SetInteger("BytesUsed", bytes_used);
+ }
+ result->Set("RasterSource", std::move(dictionary));
+ return result;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h
index 82309bd8d4c..c7fa5fa0d74 100644
--- a/chromium/cc/layers/picture_layer_impl.h
+++ b/chromium/cc/layers/picture_layer_impl.h
@@ -15,6 +15,7 @@
#include "cc/cc_export.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
+#include "cc/layers/tile_size_calculator.h"
#include "cc/paint/image_id.h"
#include "cc/tiles/picture_layer_tiling.h"
#include "cc/tiles/picture_layer_tiling_set.h"
@@ -51,22 +52,25 @@ class CC_EXPORT PictureLayerImpl
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
void NotifyTileStateChanged(const Tile* tile) override;
+ gfx::Rect GetDamageRect() const override;
+ void ResetChangeTracking() override;
void ResetRasterScale();
void DidBeginTracing() override;
void ReleaseResources() override;
void ReleaseTileResources() override;
void RecreateTileResources() override;
Region GetInvalidationRegionForDebugging() override;
+ gfx::Rect GetEnclosingRectInTargetSpace() const override;
// PictureLayerTilingClient overrides.
std::unique_ptr<Tile> CreateTile(const Tile::CreateInfo& info) override;
- gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override;
+ gfx::Size CalculateTileSize(const gfx::Size& content_bounds) override;
const Region* GetPendingInvalidation() override;
const PictureLayerTiling* GetPendingOrActiveTwinTiling(
const PictureLayerTiling* tiling) const override;
bool HasValidTilePriorities() const override;
bool RequiresHighResToDraw() const override;
- gfx::Rect GetEnclosingRectInTargetSpace() const override;
+ const PaintWorkletRecordMap& GetPaintWorkletRecords() const override;
// ImageAnimationController::AnimationDriver overrides.
bool ShouldAnimate(PaintImage::Id paint_image_id) const override;
@@ -74,9 +78,16 @@ class CC_EXPORT PictureLayerImpl
void set_gpu_raster_max_texture_size(gfx::Size gpu_raster_max_texture_size) {
gpu_raster_max_texture_size_ = gpu_raster_max_texture_size;
}
- void UpdateRasterSource(scoped_refptr<RasterSource> raster_source,
- Region* new_invalidation,
- const PictureLayerTilingSet* pending_set);
+
+ gfx::Size gpu_raster_max_texture_size() {
+ return gpu_raster_max_texture_size_;
+ }
+
+ void UpdateRasterSource(
+ scoped_refptr<RasterSource> raster_source,
+ Region* new_invalidation,
+ const PictureLayerTilingSet* pending_set,
+ const PaintWorkletRecordMap* pending_paint_worklet_records);
bool UpdateTiles();
// Returns true if the LCD state changed.
bool UpdateCanUseLCDTextAfterCommit();
@@ -123,10 +134,23 @@ class CC_EXPORT PictureLayerImpl
ImageInvalidationResult InvalidateRegionForImages(
const PaintImageIdFlatSet& images_to_invalidate);
- bool RasterSourceUsesLCDTextForTesting() const { return can_use_lcd_text_; }
+ bool can_use_lcd_text() const { return can_use_lcd_text_; }
const Region& InvalidationForTesting() const { return invalidation_; }
+ // Set the paint result (PaintRecord) for a given PaintWorkletInput.
+ void SetPaintWorkletRecord(scoped_refptr<PaintWorkletInput>,
+ sk_sp<PaintRecord>);
+
+ // Retrieve the map of PaintWorkletInputs to their painted results
+ // (PaintRecords). If a PaintWorkletInput has not been painted yet, it will
+ // map to nullptr.
+ const PaintWorkletRecordMap& GetPaintWorkletRecordMap() const {
+ return paint_worklet_records_;
+ }
+
+ gfx::Size content_bounds() { return content_bounds_; }
+
protected:
PictureLayerImpl(LayerTreeImpl* tree_impl,
int id,
@@ -159,6 +183,12 @@ class CC_EXPORT PictureLayerImpl
void RegisterAnimatedImages();
void UnregisterAnimatedImages();
+ std::unique_ptr<base::DictionaryValue> LayerAsJson() const override;
+
+ // Set the collection of PaintWorkletInputs that are part of this layer.
+ void SetPaintWorkletInputs(
+ const std::vector<scoped_refptr<PaintWorkletInput>>& inputs);
+
PictureLayerImpl* twin_layer_;
std::unique_ptr<PictureLayerTilingSet> tilings_;
@@ -207,6 +237,20 @@ class CC_EXPORT PictureLayerImpl
// of comparing pointers, since objects pointed to are not guaranteed to
// exist.
std::vector<PictureLayerTiling*> last_append_quads_tilings_;
+
+ // The set of PaintWorkletInputs that are part of this PictureLayerImpl, and
+ // their painted results (if any). During commit, Blink hands us a set of
+ // PaintWorkletInputs that are part of this layer. These are then painted
+ // asynchronously on a worklet thread, triggered from
+ // |LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation|.
+ PaintWorkletRecordMap paint_worklet_records_;
+
+ gfx::Size content_bounds_;
+ TileSizeCalculator tile_size_calculator_;
+
+ // Denotes an area that is damaged and needs redraw. This is in the layer's
+ // space.
+ gfx::Rect damage_rect_;
};
} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index d98fed6c1d0..1949b3524f2 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -31,6 +31,7 @@
#include "cc/test/layer_test_common.h"
#include "cc/test/skia_common.h"
#include "cc/test/test_layer_tree_host_base.h"
+#include "cc/test/test_paint_worklet_input.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/tiles/tiling_set_raster_queue_all.h"
#include "cc/tiles/tiling_set_raster_queue_required.h"
@@ -80,7 +81,6 @@ class PictureLayerImplTest : public TestLayerTreeHostBase {
LayerTreeSettings CreateSettings() override {
LayerTreeSettings settings;
settings.commit_to_active_tree = false;
- settings.layer_transforms_should_scale_layer_contents = true;
settings.create_low_res_tiling = true;
return settings;
}
@@ -721,8 +721,7 @@ TEST_F(PictureLayerImplTest, ScaledBoundsOverflowInt) {
gfx::Rect(layer_bounds);
viz::SharedQuadState state;
active_layer()->PopulateScaledSharedQuadState(
- &state, adjusted_scale, adjusted_scale,
- active_layer()->contents_opaque());
+ &state, adjusted_scale, active_layer()->contents_opaque());
}
TEST_F(PictureLayerImplTest, PinchGestureTilings) {
@@ -1158,7 +1157,7 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
// Mask layers dont create low res since they always fit on one tile.
std::unique_ptr<FakePictureLayerImpl> mask =
- FakePictureLayerImpl::CreateSingleTextureMaskWithRasterSource(
+ FakePictureLayerImpl::CreateMaskWithRasterSource(
host_impl()->pending_tree(), 3, pending_raster_source);
mask->SetBounds(layer_bounds);
mask->SetDrawsContent(true);
@@ -1191,7 +1190,7 @@ TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) {
SetupPendingTree(valid_raster_source);
std::unique_ptr<FakePictureLayerImpl> mask_ptr =
- FakePictureLayerImpl::CreateSingleTextureMaskWithRasterSource(
+ FakePictureLayerImpl::CreateMaskWithRasterSource(
host_impl()->pending_tree(), 3, valid_raster_source);
mask_ptr->SetBounds(layer_bounds);
mask_ptr->SetDrawsContent(true);
@@ -1324,7 +1323,7 @@ TEST_F(PictureLayerImplTest, ScaledMaskLayer) {
SetupPendingTree(valid_raster_source);
std::unique_ptr<FakePictureLayerImpl> mask_ptr =
- FakePictureLayerImpl::CreateSingleTextureMaskWithRasterSource(
+ FakePictureLayerImpl::CreateMaskWithRasterSource(
host_impl()->pending_tree(), 3, valid_raster_source);
mask_ptr->SetBounds(layer_bounds);
mask_ptr->SetDrawsContent(true);
@@ -3375,7 +3374,7 @@ TEST_F(PictureLayerImplTest, IgnoreOcclusionOnSolidColorMask) {
scoped_refptr<FakeRasterSource> pending_raster_source =
FakeRasterSource::CreateFilledSolidColor(layer_bounds);
SetupPendingTree(std::move(pending_raster_source), gfx::Size(), Region(),
- Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
host_impl()->pending_tree()->SetDeviceScaleFactor(2.f);
ActivateTree();
@@ -4934,7 +4933,7 @@ TEST_F(PictureLayerImplTest, UpdateLCDInvalidatesPendingTree) {
FakeRasterSource::CreateFilledLCD(layer_bounds);
SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region());
- EXPECT_TRUE(pending_layer()->RasterSourceUsesLCDTextForTesting());
+ EXPECT_TRUE(pending_layer()->can_use_lcd_text());
EXPECT_TRUE(pending_layer()->HighResTiling()->has_tiles());
std::vector<Tile*> tiles =
pending_layer()->HighResTiling()->AllTilesForTesting();
@@ -4942,7 +4941,7 @@ TEST_F(PictureLayerImplTest, UpdateLCDInvalidatesPendingTree) {
pending_layer()->SetContentsOpaque(false);
pending_layer()->UpdateCanUseLCDTextAfterCommit();
- EXPECT_FALSE(pending_layer()->RasterSourceUsesLCDTextForTesting());
+ EXPECT_FALSE(pending_layer()->can_use_lcd_text());
EXPECT_TRUE(pending_layer()->HighResTiling()->has_tiles());
std::vector<Tile*> new_tiles =
pending_layer()->HighResTiling()->AllTilesForTesting();
@@ -5536,5 +5535,88 @@ TEST_F(PictureLayerImplTest, AnimatedImages) {
EXPECT_FALSE(active_layer()->ShouldAnimate(image2.stable_id()));
}
+TEST_F(PictureLayerImplTest, PaintWorkletInputs) {
+ gfx::Size layer_bounds(1000, 1000);
+
+ // Set up a raster source with 2 PaintWorkletInputs.
+ auto recording_source = FakeRecordingSource::CreateRecordingSource(
+ gfx::Rect(layer_bounds), layer_bounds);
+ scoped_refptr<TestPaintWorkletInput> input1 =
+ base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(100, 100));
+ PaintImage image1 = CreatePaintWorkletPaintImage(input1);
+ scoped_refptr<TestPaintWorkletInput> input2 =
+ base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(50, 50));
+ PaintImage image2 = CreatePaintWorkletPaintImage(input2);
+ recording_source->add_draw_image(image1, gfx::Point(100, 100));
+ recording_source->add_draw_image(image2, gfx::Point(500, 500));
+ recording_source->Rerecord();
+ scoped_refptr<RasterSource> raster_source =
+ recording_source->CreateRasterSource();
+
+ // All inputs should be registered on the pending layer.
+ SetupPendingTree(raster_source, gfx::Size(), Region(gfx::Rect(layer_bounds)));
+ EXPECT_EQ(pending_layer()->GetPaintWorkletRecordMap().size(), 2u);
+ EXPECT_TRUE(pending_layer()->GetPaintWorkletRecordMap().contains(input1));
+ EXPECT_TRUE(pending_layer()->GetPaintWorkletRecordMap().contains(input2));
+
+ // Specify a record for one of the inputs.
+ sk_sp<PaintRecord> record1 = sk_make_sp<PaintOpBuffer>();
+ pending_layer()->SetPaintWorkletRecord(input1, record1);
+
+ // Now activate and make sure the active layer is registered as well, with the
+ // appropriate record.
+ ActivateTree();
+ EXPECT_EQ(active_layer()->GetPaintWorkletRecordMap().size(), 2u);
+ auto it = active_layer()->GetPaintWorkletRecordMap().find(input1);
+ ASSERT_NE(it, active_layer()->GetPaintWorkletRecordMap().end());
+ EXPECT_EQ(it->second, record1);
+ EXPECT_TRUE(active_layer()->GetPaintWorkletRecordMap().contains(input2));
+
+ // Committing new PaintWorkletInputs (in a new raster source) should replace
+ // the previous ones.
+ recording_source = FakeRecordingSource::CreateRecordingSource(
+ gfx::Rect(layer_bounds), layer_bounds);
+ scoped_refptr<TestPaintWorkletInput> input3 =
+ base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(12, 12));
+ PaintImage image3 = CreatePaintWorkletPaintImage(input3);
+ recording_source->add_draw_image(image3, gfx::Point(10, 10));
+ recording_source->Rerecord();
+ raster_source = recording_source->CreateRasterSource();
+
+ SetupPendingTree(raster_source, gfx::Size(), Region(gfx::Rect(layer_bounds)));
+ EXPECT_EQ(pending_layer()->GetPaintWorkletRecordMap().size(), 1u);
+ EXPECT_TRUE(pending_layer()->GetPaintWorkletRecordMap().contains(input3));
+}
+
+TEST_F(PictureLayerImplTest, NoTilingsUsesScaleOne) {
+ std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create();
+
+ gfx::Size layer_bounds(1000, 10000);
+ scoped_refptr<FakeRasterSource> active_raster_source =
+ FakeRasterSource::CreateEmpty(layer_bounds);
+ SetupPendingTree(active_raster_source);
+ ActivateTree();
+
+ active_layer()->SetContentsOpaque(true);
+ active_layer()->draw_properties().visible_layer_rect =
+ gfx::Rect(0, 0, 1000, 1000);
+ active_layer()->UpdateTiles();
+
+ ASSERT_FALSE(active_layer()->HighResTiling());
+
+ AppendQuadsData data;
+ active_layer()->WillDraw(DRAW_MODE_HARDWARE, nullptr);
+ active_layer()->AppendQuads(render_pass.get(), &data);
+ active_layer()->DidDraw(nullptr);
+
+ // One checkerboard quad.
+ EXPECT_EQ(1u, render_pass->quad_list.size());
+
+ auto* shared_quad_state = render_pass->quad_list.begin()->shared_quad_state;
+ // We should use scale 1 here, so the layer rect should be full layer bounds
+ // and the transform should be identity.
+ EXPECT_RECT_EQ(gfx::Rect(1000, 10000), shared_quad_state->quad_layer_rect);
+ EXPECT_TRUE(shared_quad_state->quad_to_target_transform.IsIdentity());
+}
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc
index 6acd6825c0b..ca739ac2085 100644
--- a/chromium/cc/layers/render_surface_impl.cc
+++ b/chromium/cc/layers/render_surface_impl.cc
@@ -13,9 +13,9 @@
#include "cc/base/math_util.h"
#include "cc/debug/debug_colors.h"
#include "cc/layers/append_quads_data.h"
+#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
#include "cc/trees/damage_tracker.h"
-#include "cc/trees/draw_property_utils.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/occlusion.h"
@@ -126,6 +126,13 @@ LayerImpl* RenderSurfaceImpl::MaskLayer() {
return layer_tree_impl_->LayerById(mask_layer_id);
}
+LayerImpl* RenderSurfaceImpl::BackdropMaskLayer() const {
+ ElementId mask_element_id = OwningEffectNode()->backdrop_mask_element_id;
+ if (!mask_element_id)
+ return nullptr;
+ return layer_tree_impl_->LayerByElementId(mask_element_id);
+}
+
bool RenderSurfaceImpl::HasMask() const {
return OwningEffectNode()->mask_layer_id != Layer::INVALID_ID;
}
@@ -416,12 +423,19 @@ void RenderSurfaceImpl::AppendQuads(DrawMode draw_mode,
GetDebugBorderWidth());
}
+ DCHECK(!(MaskLayer() && BackdropMaskLayer()))
+ << "Can't support both a mask_layer and a backdrop_mask_layer";
+ bool mask_applies_to_backdrop = BackdropMaskLayer();
+ PictureLayerImpl* mask_layer =
+ mask_applies_to_backdrop
+ ? static_cast<PictureLayerImpl*>(BackdropMaskLayer())
+ : static_cast<PictureLayerImpl*>(MaskLayer());
+
viz::ResourceId mask_resource_id = 0;
gfx::Size mask_texture_size;
gfx::RectF mask_uv_rect;
gfx::Vector2dF surface_contents_scale =
OwningEffectNode()->surface_contents_scale;
- PictureLayerImpl* mask_layer = static_cast<PictureLayerImpl*>(MaskLayer());
// Resourceless mode does not support masks.
if (draw_mode != DRAW_MODE_RESOURCELESS_SOFTWARE && mask_layer &&
mask_layer->DrawsContent() && !mask_layer->bounds().IsEmpty()) {
@@ -435,10 +449,6 @@ void RenderSurfaceImpl::AppendQuads(DrawMode draw_mode,
"mask_layer_gpu_memory_usage",
mask_layer->GPUMemoryUsageInBytes());
- if (mask_layer->mask_type() == Layer::LayerMaskType::MULTI_TEXTURE_MASK) {
- TileMaskLayer(render_pass, shared_quad_state, unoccluded_content_rect);
- return;
- }
gfx::SizeF mask_uv_size;
mask_layer->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
&mask_uv_size);
@@ -457,199 +467,10 @@ void RenderSurfaceImpl::AppendQuads(DrawMode draw_mode,
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>();
quad->SetNew(shared_quad_state, content_rect(), unoccluded_content_rect, id(),
mask_resource_id, mask_uv_rect, mask_texture_size,
- surface_contents_scale, FiltersOrigin(), tex_coord_rect,
+ mask_applies_to_backdrop, surface_contents_scale,
+ FiltersOrigin(), tex_coord_rect,
!layer_tree_impl_->settings().enable_edge_anti_aliasing,
OwningEffectNode()->backdrop_filter_quality);
}
-void RenderSurfaceImpl::TileMaskLayer(
- viz::RenderPass* render_pass,
- viz::SharedQuadState* shared_quad_state,
- const gfx::Rect& unoccluded_content_rect) {
- DCHECK(MaskLayer());
- DCHECK(Filters().IsEmpty());
-
- LayerImpl* mask_layer = MaskLayer();
- gfx::Vector2dF owning_layer_to_surface_contents_scale =
- OwningEffectNode()->surface_contents_scale;
-
- // Use the picture layer's AppendQuads logic to generate TileDrawQuads. These
- // DrawQuads are used to generate tiled RenderPassDrawQuad for the mask.
- std::unique_ptr<viz::RenderPass> temp_render_pass = viz::RenderPass::Create();
- AppendQuadsData temp_append_quads_data;
- mask_layer->AppendQuads(temp_render_pass.get(), &temp_append_quads_data);
-
- auto* temp_quad = temp_render_pass->quad_list.front();
- if (!temp_quad)
- return;
-
- // There are two spaces we are dealing with here:
- // 1. quad space: This is the space where the draw quads generated by the
- // PictureLayerImpl's logic are in. In other words, this is the space where
- // the |temp_quad|'s rect is in.
- // 2. surface space: This is the contents space of |this| render surface.
- // Since |mask_layer|'s target is the render surface it's masking, the surface
- // space is also the target space for the quads generated by
- // PictureLayerImpl's logic.
-
- gfx::Transform quad_space_to_surface_space_transform =
- temp_quad->shared_quad_state->quad_to_target_transform;
- // This transform should be a 2d scale + offset, so would be invertible.
- gfx::Transform surface_space_to_quad_space_transform;
- bool invertible = quad_space_to_surface_space_transform.GetInverse(
- &surface_space_to_quad_space_transform);
- DCHECK(invertible) << "RenderSurfaceImpl::TileMaskLayer created quads with "
- "non-invertible transform.";
-
- // While converting from the TileDrawQuads to RenderPassDrawQuads, we keep the
- // quad rects in the same space, and modify every other rect that is not in
- // quad space accordingly.
-
- // The |shared_quad_state| being passed in is generated with |this| render
- // surface's draw properties. It holds a transform from the surface contents
- // space to the surface target space. We want to change the origin space to
- // match the |mask_layer|'s quad space, so we must include the transform from
- // the quad space to the surface contents space. Then the transform is from
- // the |mask_layer|'s quad space to our target space.
- shared_quad_state->quad_to_target_transform.PreconcatTransform(
- quad_space_to_surface_space_transform);
-
- // Next, we need to modify the rects on |shared_quad_state| that are in
- // surface's "quad space" (surface space) to quad space.
- shared_quad_state->quad_layer_rect = MathUtil::ProjectEnclosingClippedRect(
- surface_space_to_quad_space_transform,
- shared_quad_state->quad_layer_rect);
- shared_quad_state->visible_quad_layer_rect =
- MathUtil::ProjectEnclosingClippedRect(
- surface_space_to_quad_space_transform,
- shared_quad_state->visible_quad_layer_rect);
-
- // The |shared_quad_state|'s |quad_layer_rect| and |visible_quad_layer_rect|
- // is set from content_rect(). content_rect() defines the size of the source
- // texture to be masked. PictureLayerImpl's generated |quad_layer_rect| and
- // |visible_quad_layer_rect| is from the mask layer's |bounds| and
- // |visible_layer_rect|. These rect defines the size of the mask texture. The
- // intersection of the two rects is the rect we can draw.
- shared_quad_state->quad_layer_rect.Intersect(
- temp_quad->shared_quad_state->quad_layer_rect);
- shared_quad_state->visible_quad_layer_rect.Intersect(
- temp_quad->shared_quad_state->visible_quad_layer_rect);
-
- // Cache content_rect() and |unoccluded_content_rect| in quad space.
- gfx::Rect content_rect_in_quad_space = MathUtil::MapEnclosingClippedRect(
- surface_space_to_quad_space_transform, content_rect());
- gfx::Rect unoccluded_content_rect_in_quad_space =
- MathUtil::MapEnclosingClippedRect(surface_space_to_quad_space_transform,
- unoccluded_content_rect);
-
- // Generate RenderPassDrawQuads based on the temporary quads created by
- // |mask_layer|.
- for (auto* temp_quad : temp_render_pass->quad_list) {
- gfx::Rect temp_quad_rect = temp_quad->rect;
- // If the |temp_quad_rect| is entirely outside render surface's
- // content_rect(), ignore the quad.
- if (!temp_quad_rect.Intersects(content_rect_in_quad_space))
- continue;
-
- // We only care about the quads that are inside the content_rect().
- gfx::Rect quad_rect =
- gfx::IntersectRects(temp_quad_rect, content_rect_in_quad_space);
-
- gfx::Rect visible_quad_rect =
- gfx::IntersectRects(quad_rect, unoccluded_content_rect_in_quad_space);
- if (visible_quad_rect.IsEmpty())
- continue;
-
- // |tex_coord_rect| is non-normalized sub-rect of the render surface's
- // texture that is being masked. Its origin is (0,0) and it is in surface
- // space. For example the |tex_coord_rect| for the entire texture would be
- // (0,0 content_rect.width X content_rect.height).
-
- // In order to calculate the |tex_coord_rect|, we calculate what quad's rect
- // would be masking in the surface contents space, then remove the offset.
- gfx::RectF tex_coord_rect = MathUtil::MapClippedRect(
- quad_space_to_surface_space_transform, gfx::RectF(quad_rect));
- tex_coord_rect.Offset(-content_rect().OffsetFromOrigin());
-
- constexpr float backdrop_filter_quality = 1.0;
- switch (temp_quad->material) {
- case viz::DrawQuad::Material::kTiledContent: {
- DCHECK_EQ(1U, temp_quad->resources.count);
- // When the |temp_quad| is actually a texture, we need to calculate
- // |mask_uv_rect|. The |mask_uv_rect| is the normalized sub-rect for
- // applying the mask's texture. To get |mask_uv_rect|, we need the newly
- // calculated |quad_rect| in the texture's space, then normalized by the
- // texture's size.
-
- // We are applying the |temp_quad|'s texture as a mask, so we start with
- // the |tex_coord_rect| of the |temp_quad|.
- gfx::RectF temp_tex_coord_rect =
- viz::TileDrawQuad::MaterialCast(temp_quad)->tex_coord_rect;
-
- // The |quad_rect| is in the same space as |temp_quad_rect|. Calculate
- // the scale transform between the texture space and the quad space.
- float scale_x = temp_tex_coord_rect.width() / temp_quad_rect.width();
- float scale_y = temp_tex_coord_rect.height() / temp_quad_rect.height();
- // Start by setting up the correct size of mask_uv_rect in texture
- // space.
- gfx::RectF mask_uv_rect(quad_rect.width() * scale_x,
- quad_rect.height() * scale_y);
-
- // Now figure out what is the correct offset. Start with the original
- // temp_tex_coord_rect's offset.
- mask_uv_rect.Offset(temp_tex_coord_rect.OffsetFromOrigin());
- // Next figure out what offset to apply by checking the difference in
- // offset between |temp_quad_rect| and |quad_rect| which is
- // intersected by the content_rect().
- gfx::Vector2dF offset(quad_rect.OffsetFromOrigin());
- offset -= temp_quad_rect.OffsetFromOrigin();
- // Convert the difference in offset into texture space.
- offset.Scale(scale_x, scale_y);
- mask_uv_rect.Offset(offset);
-
- // |mask_uv_rect| is normalized to [0..1] by the |mask_texture_size|.
- gfx::Size mask_texture_size =
- viz::TileDrawQuad::MaterialCast(temp_quad)->texture_size;
- mask_uv_rect.Scale(1.f / mask_texture_size.width(),
- 1.f / mask_texture_size.height());
-
- auto* quad =
- render_pass->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>();
- quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, id(),
- temp_quad->resources.ids[0], mask_uv_rect,
- mask_texture_size, owning_layer_to_surface_contents_scale,
- FiltersOrigin(), tex_coord_rect,
- !layer_tree_impl_->settings().enable_edge_anti_aliasing,
- backdrop_filter_quality);
- } break;
- case viz::DrawQuad::Material::kSolidColor: {
- SkColor temp_color =
- viz::SolidColorDrawQuad::MaterialCast(temp_quad)->color;
- // Check the alpha channel of the color. We apply the mask by
- // multiplying with the alpha channel, so if the alpha channel is
- // transparent, we skip this quad.
- if (SkColorGetA(temp_color) == SK_AlphaTRANSPARENT)
- continue;
- SkAlpha solid = SK_AlphaOPAQUE;
- DCHECK_EQ(SkColorGetA(temp_color), solid);
-
- auto* quad =
- render_pass->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>();
- quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, id(), 0,
- gfx::RectF(), gfx::Size(),
- owning_layer_to_surface_contents_scale, FiltersOrigin(),
- tex_coord_rect,
- !layer_tree_impl_->settings().enable_edge_anti_aliasing,
- backdrop_filter_quality);
- } break;
- case viz::DrawQuad::Material::kDebugBorder:
- NOTIMPLEMENTED();
- break;
- default:
- NOTREACHED();
- break;
- }
- }
-}
-
} // namespace cc
diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h
index 89a270cf933..38fcaea82b9 100644
--- a/chromium/cc/layers/render_surface_impl.h
+++ b/chromium/cc/layers/render_surface_impl.h
@@ -30,6 +30,7 @@ class FilterOperations;
class Occlusion;
class LayerImpl;
class LayerTreeImpl;
+class PictureLayerImpl;
class CC_EXPORT RenderSurfaceImpl {
public:
@@ -160,6 +161,7 @@ class CC_EXPORT RenderSurfaceImpl {
const FilterOperations& Filters() const;
const FilterOperations& BackdropFilters() const;
base::Optional<gfx::RRectF> BackdropFilterBounds() const;
+ LayerImpl* BackdropMaskLayer() const;
gfx::PointF FiltersOrigin() const;
gfx::Transform SurfaceScale() const;
@@ -180,6 +182,9 @@ class CC_EXPORT RenderSurfaceImpl {
gfx::Rect GetDamageRect() const;
std::unique_ptr<viz::RenderPass> CreateRenderPass();
+ viz::ResourceId GetMaskResourceFromLayer(PictureLayerImpl* mask_layer,
+ gfx::Size* mask_texture_size,
+ gfx::RectF* mask_uv_rect) const;
void AppendQuads(DrawMode draw_mode,
viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data);
diff --git a/chromium/cc/layers/render_surface_impl_unittest.cc b/chromium/cc/layers/render_surface_impl_unittest.cc
index 89c6177b3b0..eed5071141d 100644
--- a/chromium/cc/layers/render_surface_impl_unittest.cc
+++ b/chromium/cc/layers/render_surface_impl_unittest.cc
@@ -76,7 +76,6 @@ static std::unique_ptr<viz::RenderPass> DoAppendQuadsWithScaledMask(
FakeRasterSource::CreateFilledSolidColor(layer_size);
LayerTreeSettings settings;
- settings.layer_transforms_should_scale_layer_contents = true;
LayerTestCommon::LayerImplTest impl(settings);
std::unique_ptr<LayerImpl> root =
LayerImpl::Create(impl.host_impl()->active_tree(), 2);
@@ -147,7 +146,7 @@ TEST(RenderSurfaceLayerImplTest, ResourcelessAppendQuadsSkipMask) {
TEST(RenderSurfaceLayerImplTest,
AppendQuadsWithSolidColorMaskAndDeviceScaleFactor) {
std::unique_ptr<viz::RenderPass> render_pass = DoAppendQuadsWithScaledMask(
- DRAW_MODE_HARDWARE, 2.f, Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ DRAW_MODE_HARDWARE, 2.f, Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
DCHECK(render_pass->quad_list.front());
const viz::RenderPassDrawQuad* quad =
viz::RenderPassDrawQuad::MaterialCast(render_pass->quad_list.front());
diff --git a/chromium/cc/layers/render_surface_unittest.cc b/chromium/cc/layers/render_surface_unittest.cc
index 577594b0abe..5eac17c49ed 100644
--- a/chromium/cc/layers/render_surface_unittest.cc
+++ b/chromium/cc/layers/render_surface_unittest.cc
@@ -21,6 +21,8 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/transform.h"
+#include "cc/test/fake_raster_source.h"
+
namespace cc {
namespace {
@@ -63,7 +65,7 @@ class FakePictureLayerImplForRenderSurfaceTest : public FakePictureLayerImpl {
render_pass->CreateAndAppendSharedQuadState();
float max_contents_scale = 1.f;
PopulateScaledSharedQuadState(shared_quad_state, max_contents_scale,
- max_contents_scale, contents_opaque());
+ contents_opaque());
bool needs_blending = false;
for (const auto& rect : quad_rects_) {
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::TileDrawQuad>();
@@ -76,7 +78,7 @@ class FakePictureLayerImplForRenderSurfaceTest : public FakePictureLayerImpl {
FakePictureLayerImplForRenderSurfaceTest(LayerTreeImpl* tree_impl, int id)
: FakePictureLayerImpl(tree_impl,
id,
- Layer::LayerMaskType::MULTI_TEXTURE_MASK) {}
+ Layer::LayerMaskType::SINGLE_TEXTURE_MASK) {}
std::vector<gfx::Rect> quad_rects_;
};
@@ -239,75 +241,6 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectRenderPass) {
EXPECT_EQ(origin, pass->transform_to_root_target);
}
-TEST(RenderSurfaceTest, SanityCheckSurfaceDropsOccludedRenderPassDrawQuads) {
- FakeImplTaskRunnerProvider task_runner_provider;
- TestTaskGraphRunner task_graph_runner;
- std::unique_ptr<LayerTreeFrameSink> layer_tree_frame_sink =
- FakeLayerTreeFrameSink::Create3d();
- FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
- // Set a big enough viewport to show the entire render pass.
- host_impl.active_tree()->SetDeviceViewportSize(gfx::Size(1000, 1000));
-
- std::unique_ptr<LayerImpl> root_layer =
- LayerImpl::Create(host_impl.active_tree(), 1);
-
- int owning_layer_id = 2;
- std::unique_ptr<LayerImpl> owning_layer =
- LayerImpl::Create(host_impl.active_tree(), owning_layer_id);
-
- int mask_layer_id = 3;
- std::unique_ptr<FakePictureLayerImplForRenderSurfaceTest> mask_layer =
- FakePictureLayerImplForRenderSurfaceTest::CreateMask(
- host_impl.active_tree(), mask_layer_id);
- mask_layer->SetBounds(gfx::Size(200, 100));
- mask_layer->SetDrawsContent(true);
- std::vector<gfx::Rect> quad_rects;
- quad_rects.push_back(gfx::Rect(0, 0, 100, 100));
- quad_rects.push_back(gfx::Rect(100, 0, 100, 100));
- mask_layer->SetQuadRectsForTesting(quad_rects);
-
- owning_layer->SetBounds(gfx::Size(200, 100));
- owning_layer->SetDrawsContent(true);
- owning_layer->test_properties()->SetMaskLayer(std::move(mask_layer));
- root_layer->test_properties()->AddChild(std::move(owning_layer));
- host_impl.active_tree()->SetRootLayerForTesting(std::move(root_layer));
- host_impl.SetVisible(true);
- host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
- host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
- host_impl.active_tree()->UpdateDrawProperties();
-
- ASSERT_TRUE(
- GetRenderSurface(host_impl.active_tree()->LayerById(owning_layer_id)));
- RenderSurfaceImpl* render_surface =
- GetRenderSurface(host_impl.active_tree()->LayerById(owning_layer_id));
-
- gfx::Rect content_rect(0, 0, 200, 100);
- gfx::Rect occluded(0, 0, 100, 100);
-
- render_surface->SetContentRectForTesting(content_rect);
- render_surface->set_occlusion_in_content_space(
- Occlusion(gfx::Transform(), SimpleEnclosedRegion(occluded),
- SimpleEnclosedRegion(occluded)));
-
- std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create();
- AppendQuadsData append_quads_data;
-
- render_surface->AppendQuads(DRAW_MODE_HARDWARE, render_pass.get(),
- &append_quads_data);
-
- ASSERT_EQ(1u, render_pass->shared_quad_state_list.size());
- viz::SharedQuadState* shared_quad_state =
- render_pass->shared_quad_state_list.front();
-
- EXPECT_EQ(content_rect,
- gfx::Rect(shared_quad_state->visible_quad_layer_rect));
-
- // The quad (0, 0, 100, 100) is occluded and should be dropped.
- ASSERT_EQ(1u, render_pass->quad_list.size());
- EXPECT_EQ(gfx::Rect(100, 0, 100, 100).ToString(),
- render_pass->quad_list.front()->rect.ToString());
-}
-
TEST(RenderSurfaceTest, SanityCheckSurfaceIgnoreMaskLayerOcclusion) {
FakeImplTaskRunnerProvider task_runner_provider;
TestTaskGraphRunner task_graph_runner;
@@ -328,7 +261,11 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceIgnoreMaskLayerOcclusion) {
std::unique_ptr<FakePictureLayerImplForRenderSurfaceTest> mask_layer =
FakePictureLayerImplForRenderSurfaceTest::CreateMask(
host_impl.active_tree(), mask_layer_id);
+
mask_layer->SetBounds(gfx::Size(200, 100));
+ scoped_refptr<FakeRasterSource> raster_source(
+ FakeRasterSource::CreateFilled(mask_layer->bounds()));
+ mask_layer->SetRasterSourceOnActive(raster_source, Region());
mask_layer->SetDrawsContent(true);
std::vector<gfx::Rect> quad_rects;
quad_rects.push_back(gfx::Rect(0, 0, 100, 100));
@@ -345,10 +282,9 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceIgnoreMaskLayerOcclusion) {
host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl.active_tree()->UpdateDrawProperties();
- ASSERT_TRUE(
- GetRenderSurface(host_impl.active_tree()->LayerById(owning_layer_id)));
RenderSurfaceImpl* render_surface =
GetRenderSurface(host_impl.active_tree()->LayerById(owning_layer_id));
+ ASSERT_TRUE(render_surface);
gfx::Rect content_rect(0, 0, 200, 100);
gfx::Rect occluded(0, 0, 200, 100);
@@ -373,14 +309,9 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceIgnoreMaskLayerOcclusion) {
EXPECT_EQ(content_rect,
gfx::Rect(shared_quad_state->visible_quad_layer_rect));
-
- // Neither of the two quads should be occluded since mask occlusion is
- // ignored.
- ASSERT_EQ(2u, render_pass->quad_list.size());
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
+ ASSERT_EQ(1u, render_pass->quad_list.size());
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 100).ToString(),
render_pass->quad_list.front()->rect.ToString());
- EXPECT_EQ(gfx::Rect(100, 0, 100, 100).ToString(),
- render_pass->quad_list.back()->rect.ToString());
}
} // namespace
diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc
index 3320d74868f..6a2dd986d9d 100644
--- a/chromium/cc/layers/scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/scrollbar_layer_unittest.cc
@@ -31,6 +31,7 @@
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/occlusion_tracker.h"
#include "cc/trees/scroll_node.h"
@@ -1076,6 +1077,10 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
layer_tree_host_->SetRootLayer(layer_tree_root);
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ layer_tree_root.get(), layer_tree_host_->device_viewport_size());
+ LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
+
scrollbar_layer->SetIsDrawable(true);
scrollbar_layer->SetBounds(gfx::Size(100, 100));
layer_tree_root->SetScrollable(gfx::Size(100, 200));
@@ -1134,6 +1139,10 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
layer_tree_host_->SetRootLayer(layer_tree_root);
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ layer_tree_root.get(), layer_tree_host_->device_viewport_size());
+ LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
+
scrollbar_layer->SetIsDrawable(true);
scrollbar_layer->SetBounds(gfx::Size(100, 15));
scrollbar_layer->SetPosition(gfx::PointF(scrollbar_location));
@@ -1303,6 +1312,11 @@ class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ layer_tree_root.get(), layer_tree_host_->device_viewport_size());
+ inputs.device_scale_factor = test_scale;
+ LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
+
layer_tree_host_->SetViewportSizeAndScale(
layer_tree_host_->device_viewport_size(), test_scale,
layer_tree_host_->local_surface_id_allocation_from_parent());
@@ -1368,6 +1382,10 @@ class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
scrollbar_layer->fake_scrollbar()->set_location(scrollbar_rect.origin());
scrollbar_layer->fake_scrollbar()->set_track_rect(scrollbar_rect);
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ layer_tree_root.get(), layer_tree_host_->device_viewport_size());
+ inputs.device_scale_factor = test_scale;
+ LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
layer_tree_host_->SetViewportSizeAndScale(
layer_tree_host_->device_viewport_size(), test_scale,
layer_tree_host_->local_surface_id_allocation_from_parent());
diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc
index 9d4a37a49d5..6ef4249c51e 100644
--- a/chromium/cc/layers/surface_layer_impl.cc
+++ b/chromium/cc/layers/surface_layer_impl.cc
@@ -143,7 +143,7 @@ void SurfaceLayerImpl::AppendQuads(viz::RenderPass* render_pass,
render_pass->CreateAndAppendSharedQuadState();
PopulateScaledSharedQuadState(shared_quad_state, device_scale_factor,
- device_scale_factor, contents_opaque());
+ contents_opaque());
if (surface_range_.IsValid()) {
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
diff --git a/chromium/cc/layers/texture_layer.cc b/chromium/cc/layers/texture_layer.cc
index e97162e7b1e..4e1c25208f4 100644
--- a/chromium/cc/layers/texture_layer.cc
+++ b/chromium/cc/layers/texture_layer.cc
@@ -23,8 +23,7 @@ scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox(
return scoped_refptr<TextureLayer>(new TextureLayer(client));
}
-TextureLayer::TextureLayer(TextureLayerClient* client)
- : client_(client), weak_ptr_factory_(this) {}
+TextureLayer::TextureLayer(TextureLayerClient* client) : client_(client) {}
TextureLayer::~TextureLayer() = default;
diff --git a/chromium/cc/layers/texture_layer.h b/chromium/cc/layers/texture_layer.h
index dc9bd63f500..9166bd26472 100644
--- a/chromium/cc/layers/texture_layer.h
+++ b/chromium/cc/layers/texture_layer.h
@@ -175,6 +175,11 @@ class CC_EXPORT TextureLayer : public Layer, SharedBitmapIdRegistrar {
const viz::SharedBitmapId& id,
scoped_refptr<CrossThreadSharedBitmap> bitmap) override;
+ viz::TransferableResource current_transferable_resource() const {
+ return holder_ref_ ? holder_ref_->holder()->resource()
+ : viz::TransferableResource();
+ }
+
protected:
explicit TextureLayer(TextureLayerClient* client);
~TextureLayer() override;
@@ -222,7 +227,7 @@ class CC_EXPORT TextureLayer : public Layer, SharedBitmapIdRegistrar {
// TextureLayerImpl.
std::vector<viz::SharedBitmapId> to_unregister_bitmap_ids_;
- base::WeakPtrFactory<TextureLayer> weak_ptr_factory_;
+ base::WeakPtrFactory<TextureLayer> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc
index 6944908fbb2..3f82dafccf0 100644
--- a/chromium/cc/layers/texture_layer_impl.cc
+++ b/chromium/cc/layers/texture_layer_impl.cc
@@ -110,8 +110,7 @@ void TextureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
LayerTreeFrameSink* sink = layer_tree_impl()->layer_tree_frame_sink();
for (const auto& pair : to_register_bitmaps_) {
- sink->DidAllocateSharedBitmap(viz::bitmap_allocation::ToMojoHandle(
- pair.second->shared_region().Duplicate()),
+ sink->DidAllocateSharedBitmap(pair.second->shared_region().Duplicate(),
pair.first);
}
// All |to_register_bitmaps_| have been registered above, so we can move them
@@ -150,7 +149,7 @@ void TextureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
resource_id_, premultiplied_alpha_, uv_top_left_,
uv_bottom_right_, bg_color, vertex_opacity_, flipped_,
nearest_neighbor_, /*secure_output_only=*/false,
- ui::ProtectedVideoType::kClear);
+ gfx::ProtectedVideoType::kClear);
quad->set_resource_size_in_pixels(transferable_resource_.size);
ValidateQuadResources(quad);
}
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index 7aec79fdf9a..b581c5a54ba 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -32,6 +32,7 @@
#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/stub_layer_tree_host_single_thread_client.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
@@ -45,7 +46,6 @@
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/service/display/software_output_device.h"
#include "components/viz/test/fake_output_surface.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -581,7 +581,7 @@ TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleasedFirst) {
class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
public:
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -591,7 +591,7 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
bool synchronous_composite =
!HasImplThread() &&
!layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
- return std::make_unique<viz::TestLayerTreeFrameSink>(
+ return std::make_unique<TestLayerTreeFrameSink>(
compositor_context_provider, std::move(worker_context_provider),
gpu_memory_buffer_manager(), renderer_settings, ImplThreadTaskRunner(),
synchronous_composite, disable_display_vsync, refresh_rate);
@@ -1489,7 +1489,7 @@ class SoftwareTextureLayerTest : public LayerTreeTest {
LayerTreeTest::SetupTree();
}
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -1499,7 +1499,7 @@ class SoftwareTextureLayerTest : public LayerTreeTest {
bool synchronous_composite =
!HasImplThread() &&
!layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
- auto sink = std::make_unique<viz::TestLayerTreeFrameSink>(
+ auto sink = std::make_unique<TestLayerTreeFrameSink>(
nullptr, nullptr, gpu_memory_buffer_manager(), renderer_settings,
ImplThreadTaskRunner(), synchronous_composite, disable_display_vsync,
refresh_rate);
@@ -1519,7 +1519,7 @@ class SoftwareTextureLayerTest : public LayerTreeTest {
scoped_refptr<Layer> root_;
scoped_refptr<SolidColorLayer> solid_color_layer_;
scoped_refptr<TextureLayer> texture_layer_;
- viz::TestLayerTreeFrameSink* frame_sink_ = nullptr;
+ TestLayerTreeFrameSink* frame_sink_ = nullptr;
int num_frame_sinks_created_ = 0;
};
diff --git a/chromium/cc/layers/tile_size_calculator.cc b/chromium/cc/layers/tile_size_calculator.cc
new file mode 100644
index 00000000000..6c071ca3708
--- /dev/null
+++ b/chromium/cc/layers/tile_size_calculator.cc
@@ -0,0 +1,221 @@
+// Copyright 2019 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/layers/tile_size_calculator.h"
+
+#include "cc/base/math_util.h"
+#include "cc/layers/picture_layer_impl.h"
+#include "cc/trees/layer_tree_impl.h"
+
+namespace cc {
+namespace {
+// Even for really wide viewports, at some point GPU raster should use
+// less than 4 tiles to fill the viewport. This is set to 256 as a
+// sane minimum for now, but we might want to tune this for low-end.
+const int kMinHeightForGpuRasteredTile = 256;
+
+// When making odd-sized tiles, round them up to increase the chances
+// of using the same tile size.
+const int kTileRoundUp = 64;
+
+// Round GPU default tile sizes to a multiple of 32. This helps prevent
+// rounding errors during compositing.
+const int kGpuDefaultTileRoundUp = 32;
+
+// For performance reasons and to support compressed tile textures, tile
+// width and height should be an even multiple of 4 in size.
+const int kTileMinimalAlignment = 4;
+
+// This function converts the given |device_pixels_size| to the expected size
+// of content which was generated to fill it at 100%. This takes into account
+// the ceil operations that occur as device pixels are converted to/from DIPs
+// (content size must be a whole number of DIPs).
+gfx::Size ApplyDsfAdjustment(const gfx::Size& device_pixels_size, float dsf) {
+ gfx::Size content_size_in_dips =
+ gfx::ScaleToCeiledSize(device_pixels_size, 1.0f / dsf);
+ gfx::Size content_size_in_dps =
+ gfx::ScaleToCeiledSize(content_size_in_dips, dsf);
+ return content_size_in_dps;
+}
+
+// For GPU rasterization, we pick an ideal tile size using the viewport so we
+// don't need any settings. The current approach uses 4 tiles to cover the
+// viewport vertically.
+gfx::Size CalculateGpuTileSize(const gfx::Size& base_tile_size,
+ const gfx::Size& content_bounds,
+ const gfx::Size& max_tile_size) {
+ int tile_width = base_tile_size.width();
+
+ // Increase the height proportionally as the width decreases, and pad by our
+ // border texels to make the tiles exactly match the viewport.
+ int divisor = 4;
+ if (content_bounds.width() <= base_tile_size.width() / 2)
+ divisor = 2;
+ if (content_bounds.width() <= base_tile_size.width() / 4)
+ divisor = 1;
+ int tile_height =
+ MathUtil::UncheckedRoundUp(base_tile_size.height(), divisor) / divisor;
+
+ // Grow default sizes to account for overlapping border texels.
+ tile_width += 2 * PictureLayerTiling::kBorderTexels;
+ tile_height += 2 * PictureLayerTiling::kBorderTexels;
+
+ // Round GPU default tile sizes to a multiple of kGpuDefaultTileAlignment.
+ // This helps prevent rounding errors in our CA path. https://crbug.com/632274
+ tile_width = MathUtil::UncheckedRoundUp(tile_width, kGpuDefaultTileRoundUp);
+ tile_height = MathUtil::UncheckedRoundUp(tile_height, kGpuDefaultTileRoundUp);
+
+ tile_height = std::max(tile_height, kMinHeightForGpuRasteredTile);
+
+ if (!max_tile_size.IsEmpty()) {
+ tile_width = std::min(tile_width, max_tile_size.width());
+ tile_height = std::min(tile_height, max_tile_size.height());
+ }
+
+ return gfx::Size(tile_width, tile_height);
+}
+
+} // namespace
+
+// AffectingParams.
+bool TileSizeCalculator::AffectingParams::operator==(
+ const AffectingParams& other) {
+ return max_texture_size == other.max_texture_size &&
+ use_gpu_rasterization == other.use_gpu_rasterization &&
+ device_scale_factor == other.device_scale_factor &&
+ max_tile_size == other.max_tile_size &&
+ gpu_raster_max_texture_size == other.gpu_raster_max_texture_size &&
+ max_untiled_layer_size == other.max_untiled_layer_size &&
+ default_tile_size == other.default_tile_size &&
+ layer_content_bounds == other.layer_content_bounds;
+}
+
+// TileSizeCalculator.
+TileSizeCalculator::TileSizeCalculator(PictureLayerImpl* layer_impl)
+ : layer_impl_(layer_impl) {}
+
+bool TileSizeCalculator::IsAffectingParamsChanged() {
+ AffectingParams new_params = GetAffectingParams();
+
+ if (affecting_params_ == new_params)
+ return false;
+
+ affecting_params_ = new_params;
+ return true;
+}
+
+TileSizeCalculator::AffectingParams TileSizeCalculator::GetAffectingParams() {
+ AffectingParams params;
+ LayerTreeImpl* layer_tree_impl = layer_impl()->layer_tree_impl();
+ params.max_texture_size = layer_tree_impl->max_texture_size();
+ params.use_gpu_rasterization = layer_tree_impl->use_gpu_rasterization();
+ params.max_tile_size = layer_tree_impl->settings().max_gpu_raster_tile_size;
+ params.gpu_raster_max_texture_size =
+ layer_impl()->gpu_raster_max_texture_size();
+ params.device_scale_factor = layer_tree_impl->device_scale_factor();
+ params.max_untiled_layer_size =
+ layer_tree_impl->settings().max_untiled_layer_size;
+ params.default_tile_size = layer_tree_impl->settings().default_tile_size;
+ params.layer_content_bounds = layer_impl()->content_bounds();
+ return params;
+}
+
+gfx::Size TileSizeCalculator::CalculateTileSize() {
+ gfx::Size content_bounds = layer_impl()->content_bounds();
+
+ if (layer_impl()->mask_type() == Layer::LayerMaskType::SINGLE_TEXTURE_MASK) {
+ // Masks are not tiled, so if we can't cover the whole mask with one tile,
+ // we shouldn't have such a tiling at all.
+ DCHECK_LE(content_bounds.width(),
+ layer_impl()->layer_tree_impl()->max_texture_size());
+ DCHECK_LE(content_bounds.height(),
+ layer_impl()->layer_tree_impl()->max_texture_size());
+ return content_bounds;
+ }
+
+ // If |affecting_params_| is already computed and not changed, return
+ // pre-calculated tile size.
+ if (!IsAffectingParamsChanged())
+ return tile_size_;
+
+ int default_tile_width = 0;
+ int default_tile_height = 0;
+ if (affecting_params_.use_gpu_rasterization) {
+ gfx::Size max_tile_size = affecting_params_.max_tile_size;
+
+ // Calculate |base_tile_size| based on |gpu_raster_max_texture_size|,
+ // adjusting for ceil operations that may occur due to DSF.
+ gfx::Size base_tile_size =
+ ApplyDsfAdjustment(affecting_params_.gpu_raster_max_texture_size,
+ affecting_params_.device_scale_factor);
+
+ // Set our initial size assuming a |base_tile_size| equal to our
+ // |viewport_size|.
+ gfx::Size default_tile_size =
+ CalculateGpuTileSize(base_tile_size, content_bounds, max_tile_size);
+
+ // Use half-width GPU tiles when the content_width is greater than our
+ // calculated tile size.
+ if (content_bounds.width() > default_tile_size.width()) {
+ // Divide width by 2 and round up.
+ base_tile_size.set_width((base_tile_size.width() + 1) / 2);
+ default_tile_size =
+ CalculateGpuTileSize(base_tile_size, content_bounds, max_tile_size);
+ }
+
+ default_tile_width = default_tile_size.width();
+ default_tile_height = default_tile_size.height();
+ } else {
+ // For CPU rasterization we use tile-size settings.
+ int max_untiled_content_width =
+ affecting_params_.max_untiled_layer_size.width();
+ int max_untiled_content_height =
+ affecting_params_.max_untiled_layer_size.height();
+ default_tile_width = affecting_params_.default_tile_size.width();
+ default_tile_height = affecting_params_.default_tile_size.height();
+
+ // If the content width is small, increase tile size vertically.
+ // If the content height is small, increase tile size horizontally.
+ // If both are less than the untiled-size, use a single tile.
+ if (content_bounds.width() < default_tile_width)
+ default_tile_height = max_untiled_content_height;
+ if (content_bounds.height() < default_tile_height)
+ default_tile_width = max_untiled_content_width;
+ if (content_bounds.width() < max_untiled_content_width &&
+ content_bounds.height() < max_untiled_content_height) {
+ default_tile_height = max_untiled_content_height;
+ default_tile_width = max_untiled_content_width;
+ }
+ }
+
+ int tile_width = default_tile_width;
+ int tile_height = default_tile_height;
+
+ // Clamp the tile width/height to the content width/height to save space.
+ if (content_bounds.width() < default_tile_width) {
+ tile_width = std::min(tile_width, content_bounds.width());
+ tile_width = MathUtil::UncheckedRoundUp(tile_width, kTileRoundUp);
+ tile_width = std::min(tile_width, default_tile_width);
+ }
+ if (content_bounds.height() < default_tile_height) {
+ tile_height = std::min(tile_height, content_bounds.height());
+ tile_height = MathUtil::UncheckedRoundUp(tile_height, kTileRoundUp);
+ tile_height = std::min(tile_height, default_tile_height);
+ }
+
+ // Ensure that tile width and height are properly aligned.
+ tile_width = MathUtil::UncheckedRoundUp(tile_width, kTileMinimalAlignment);
+ tile_height = MathUtil::UncheckedRoundUp(tile_height, kTileMinimalAlignment);
+
+ // Under no circumstance should we be larger than the max texture size.
+ tile_width = std::min(tile_width, affecting_params_.max_texture_size);
+ tile_height = std::min(tile_height, affecting_params_.max_texture_size);
+
+ // Store the calculated tile size.
+ tile_size_ = gfx::Size(tile_width, tile_height);
+
+ return tile_size_;
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/tile_size_calculator.h b/chromium/cc/layers/tile_size_calculator.h
new file mode 100644
index 00000000000..cd455b922d2
--- /dev/null
+++ b/chromium/cc/layers/tile_size_calculator.h
@@ -0,0 +1,50 @@
+// Copyright 2019 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.
+
+#ifndef CC_LAYERS_TILE_SIZE_CALCULATOR_H_
+#define CC_LAYERS_TILE_SIZE_CALCULATOR_H_
+
+#include "cc/cc_export.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace cc {
+
+class PictureLayerImpl;
+
+// This class calculates the tile size only when the |affecting_params_|
+// or |content_bounds_| is changed.
+class CC_EXPORT TileSizeCalculator {
+ public:
+ explicit TileSizeCalculator(PictureLayerImpl* layer_impl);
+
+ gfx::Size CalculateTileSize();
+
+ private:
+ struct AffectingParams {
+ int max_texture_size = 0;
+ bool use_gpu_rasterization = false;
+ float device_scale_factor = 0.0f;
+ gfx::Size max_tile_size;
+ gfx::Size gpu_raster_max_texture_size;
+ gfx::Size max_untiled_layer_size;
+ gfx::Size default_tile_size;
+ gfx::Size layer_content_bounds;
+
+ bool operator==(const AffectingParams& other);
+ };
+
+ PictureLayerImpl* layer_impl() const { return layer_impl_; }
+ AffectingParams GetAffectingParams();
+ bool IsAffectingParamsChanged();
+
+ PictureLayerImpl* layer_impl_;
+
+ AffectingParams affecting_params_;
+
+ gfx::Size tile_size_;
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_TILE_SIZE_CALCULATOR_H_
diff --git a/chromium/cc/layers/touch_action_region.cc b/chromium/cc/layers/touch_action_region.cc
index 75da3cac02c..a84bd0e9a75 100644
--- a/chromium/cc/layers/touch_action_region.cc
+++ b/chromium/cc/layers/touch_action_region.cc
@@ -8,26 +8,22 @@
namespace cc {
-TouchActionRegion::TouchActionRegion() : region_(std::make_unique<Region>()) {}
+TouchActionRegion::TouchActionRegion() {}
TouchActionRegion::TouchActionRegion(
- const TouchActionRegion& touch_action_region)
- : map_(touch_action_region.map_),
- region_(std::make_unique<Region>(touch_action_region.region())) {}
+ const TouchActionRegion& touch_action_region) = default;
TouchActionRegion::TouchActionRegion(TouchActionRegion&& touch_action_region) =
default;
-TouchActionRegion::TouchActionRegion(
- const base::flat_map<TouchAction, Region>& region_map)
- : map_(region_map), region_(std::make_unique<Region>()) {
- for (const auto& pair : region_map) {
- region_->Union(pair.second);
- }
-}
-
TouchActionRegion::~TouchActionRegion() = default;
+Region TouchActionRegion::GetAllRegions() const {
+ Region all_regions;
+ for (const auto& pair : map_)
+ all_regions.Union(pair.second);
+ return all_regions;
+}
+
void TouchActionRegion::Union(TouchAction touch_action, const gfx::Rect& rect) {
- region_->Union(rect);
map_[touch_action].Union(rect);
}
@@ -53,7 +49,6 @@ TouchAction TouchActionRegion::GetAllowedTouchAction(
TouchActionRegion& TouchActionRegion::operator=(
const TouchActionRegion& other) {
- *region_ = *other.region_;
map_ = other.map_;
return *this;
}
diff --git a/chromium/cc/layers/touch_action_region.h b/chromium/cc/layers/touch_action_region.h
index 4322646a36d..6a8911a5f72 100644
--- a/chromium/cc/layers/touch_action_region.h
+++ b/chromium/cc/layers/touch_action_region.h
@@ -19,13 +19,15 @@ class CC_EXPORT TouchActionRegion {
TouchActionRegion();
TouchActionRegion(const TouchActionRegion& touch_action_region);
TouchActionRegion(TouchActionRegion&& touch_action_region);
- explicit TouchActionRegion(const base::flat_map<TouchAction, Region>&);
~TouchActionRegion();
void Union(TouchAction, const gfx::Rect&);
- const Region& region() const { return *region_; }
+ // Return all regions with any touch action.
+ Region GetAllRegions() const;
const Region& GetRegionForTouchAction(TouchAction) const;
+ bool IsEmpty() const { return map_.empty(); }
+
// Returns the touch actions that we are sure will be allowed at the point
// by finding the intersection of all touch actions whose regions contain the
// given point. If the map is empty, |kTouchActionAuto| is returned since no
@@ -37,10 +39,7 @@ class CC_EXPORT TouchActionRegion {
bool operator==(const TouchActionRegion& other) const;
private:
- // TODO(hayleyferr): Region could be owned directly instead of in a
- // unique_ptr if Region supported efficient moving.
base::flat_map<TouchAction, Region> map_;
- std::unique_ptr<Region> region_;
};
} // namespace cc
diff --git a/chromium/cc/layers/touch_action_region_unittest.cc b/chromium/cc/layers/touch_action_region_unittest.cc
index 1157982e6b6..e41631901e3 100644
--- a/chromium/cc/layers/touch_action_region_unittest.cc
+++ b/chromium/cc/layers/touch_action_region_unittest.cc
@@ -63,25 +63,5 @@ TEST(TouchActionRegionTest, GetAllowedTouchActionSingleMapEntry) {
touch_action_region.GetAllowedTouchAction(gfx::Point(60, 60)));
}
-TEST(TouchActionRegionTest, ConstructorFromMap) {
- gfx::Rect rect1(0, 0, 50, 50);
- gfx::Rect rect2(50, 0, 50, 50);
- base::flat_map<TouchAction, Region> region_map;
- region_map[kTouchActionPanX].Union(rect1);
- region_map[kTouchActionPanUp].Union(rect2);
- TouchActionRegion touch_action_region(region_map);
-
- Region expected_region1(rect1);
- Region expected_region2(rect2);
- Region expected_region3(rect1);
- expected_region3.Union(rect2);
-
- EXPECT_EQ(touch_action_region.GetRegionForTouchAction(kTouchActionPanX),
- expected_region1);
- EXPECT_EQ(touch_action_region.GetRegionForTouchAction(kTouchActionPanUp),
- expected_region2);
- EXPECT_EQ(touch_action_region.region(), expected_region3);
-}
-
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/ui_resource_layer_impl.cc b/chromium/cc/layers/ui_resource_layer_impl.cc
index 7eae103e9aa..cb3dea6c5bd 100644
--- a/chromium/cc/layers/ui_resource_layer_impl.cc
+++ b/chromium/cc/layers/ui_resource_layer_impl.cc
@@ -130,7 +130,7 @@ void UIResourceLayerImpl::AppendQuads(viz::RenderPass* render_pass,
quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, needs_blending,
resource, premultiplied_alpha, uv_top_left_, uv_bottom_right_,
SK_ColorTRANSPARENT, vertex_opacity_, flipped, nearest_neighbor,
- /*secure_output_only=*/false, ui::ProtectedVideoType::kClear);
+ /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
ValidateQuadResources(quad);
}
diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
index 4459afbbc22..02c682614f1 100644
--- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -96,8 +96,7 @@ AsyncLayerTreeFrameSink::AsyncLayerTreeFrameSink(
params->client_name)),
submit_begin_frame_histogram_(GetHistogramNamed(
"GraphicsPipeline.%s.SubmitCompositorFrameAfterBeginFrame",
- params->client_name)),
- weak_factory_(this) {
+ params->client_name)) {
// We should not create hit test data provider if we want to use cc layer tree
// to generated data.
if (features::IsVizHitTestingSurfaceLayerEnabled())
@@ -174,8 +173,6 @@ void AsyncLayerTreeFrameSink::SubmitCompositorFrame(
DCHECK(frame.metadata.begin_frame_ack.has_damage);
DCHECK_LE(viz::BeginFrameArgs::kStartingFrameNumber,
frame.metadata.begin_frame_ack.sequence_number);
- TRACE_EVENT1("cc,benchmark", "AsyncLayerTreeFrameSink::SubmitCompositorFrame",
- "source_frame_number_", source_frame_number_);
// It's possible to request an immediate composite from cc which will bypass
// BeginFrame. In that case, we cannot collect full graphics pipeline data.
@@ -203,12 +200,6 @@ void AsyncLayerTreeFrameSink::SubmitCompositorFrame(
}
}
- TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
- "SubmitCompositorFrame", local_surface_id_.hash());
- bool tracing_enabled;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
- &tracing_enabled);
-
base::Optional<viz::HitTestRegionList> hit_test_region_list;
if (hit_test_data_provider_)
hit_test_region_list = hit_test_data_provider_->GetHitTestData(frame);
@@ -272,9 +263,7 @@ void AsyncLayerTreeFrameSink::SubmitCompositorFrame(
"SubmitHitTestData");
compositor_frame_sink_ptr_->SubmitCompositorFrame(
- local_surface_id_, std::move(frame), std::move(hit_test_region_list),
- tracing_enabled ? base::TimeTicks::Now().since_origin().InMicroseconds()
- : 0);
+ local_surface_id_, std::move(frame), std::move(hit_test_region_list), 0);
}
void AsyncLayerTreeFrameSink::DidNotProduceFrame(
@@ -293,10 +282,10 @@ void AsyncLayerTreeFrameSink::DidNotProduceFrame(
}
void AsyncLayerTreeFrameSink::DidAllocateSharedBitmap(
- mojo::ScopedSharedBufferHandle buffer,
+ base::ReadOnlySharedMemoryRegion region,
const viz::SharedBitmapId& id) {
DCHECK(compositor_frame_sink_ptr_);
- compositor_frame_sink_ptr_->DidAllocateSharedBitmap(std::move(buffer), id);
+ compositor_frame_sink_ptr_->DidAllocateSharedBitmap(std::move(region), id);
}
void AsyncLayerTreeFrameSink::DidDeleteSharedBitmap(
@@ -319,9 +308,10 @@ void AsyncLayerTreeFrameSink::DidReceiveCompositorFrameAck(
void AsyncLayerTreeFrameSink::OnBeginFrame(
const viz::BeginFrameArgs& args,
- const viz::PresentationFeedbackMap& feedbacks) {
- for (const auto& pair : feedbacks) {
- client_->DidPresentCompositorFrame(pair.first, pair.second);
+ const viz::FrameTimingDetailsMap& timing_details) {
+ for (const auto& pair : timing_details) {
+ client_->DidPresentCompositorFrame(pair.first,
+ pair.second.presentation_feedback);
}
DCHECK_LE(pipeline_reporting_frame_times_.size(), 25u);
diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
index 5ed49023a30..1b176d0d9da 100644
--- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
@@ -9,13 +9,14 @@
#include <string>
#include <vector>
+#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "cc/mojo_embedder/mojo_embedder_export.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/common/frame_timing_details_map.h"
#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/presentation_feedback_map.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "mojo/public/cpp/bindings/binding.h"
@@ -123,7 +124,7 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink
bool hit_test_data_changed,
bool show_hit_test_borders) override;
void DidNotProduceFrame(const viz::BeginFrameAck& ack) override;
- void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
+ void DidAllocateSharedBitmap(base::ReadOnlySharedMemoryRegion region,
const viz::SharedBitmapId& id) override;
void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override;
void ForceAllocateNewId() override;
@@ -137,7 +138,7 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink
void DidReceiveCompositorFrameAck(
const std::vector<viz::ReturnedResource>& resources) override;
void OnBeginFrame(const viz::BeginFrameArgs& begin_frame_args,
- const viz::PresentationFeedbackMap& feedbacks) override;
+ const viz::FrameTimingDetailsMap& timing_details) override;
void OnBeginFramePausedChanged(bool paused) override;
void ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) override;
@@ -187,7 +188,7 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink
// Histogram metrics used to record
// GraphicsPipeline.ClientName.SubmitCompositorFrameAfterBeginFrame
base::HistogramBase* const submit_begin_frame_histogram_;
- base::WeakPtrFactory<AsyncLayerTreeFrameSink> weak_factory_;
+ base::WeakPtrFactory<AsyncLayerTreeFrameSink> weak_factory_{this};
};
} // namespace mojo_embedder
diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc
index 0a6f1d6ce29..8205b650973 100644
--- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc
@@ -292,15 +292,15 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListDuplicate) {
quad3_root_1->SetNew(shared_quad_state3_root, /*rect=*/rect3_root,
/*visible_rect=*/rect3_root, /*render_pass_id=*/3,
/*mask_resource_id=*/0, gfx::RectF(), gfx::Size(),
- gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false,
- 1.0f);
+ /*mask_applies_to_backdrop=*/false, gfx::Vector2dF(1, 1),
+ gfx::PointF(), gfx::RectF(), false, 1.0f);
auto* quad3_root_2 =
pass3_root->quad_list.AllocateAndConstruct<viz::RenderPassDrawQuad>();
quad3_root_2->SetNew(shared_quad_state3_root, /*rect=*/rect3_root,
/*visible_rect=*/rect3_root, /*render_pass_id=*/4,
/*mask_resource_id=*/0, gfx::RectF(), gfx::Size(),
- gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false,
- 1.0f);
+ /*mask_applies_to_backdrop=*/false, gfx::Vector2dF(1, 1),
+ gfx::PointF(), gfx::RectF(), false, 1.0f);
pass_list.push_back(std::move(pass3_root));
SendRenderPassList(&pass_list, /*hit_test_data_changed=*/false);
@@ -396,15 +396,15 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest,
quad2_root_1->SetNew(shared_quad_state2_root, /*rect=*/rect2_root,
/*visible_rect=*/rect2_root, /*render_pass_id=*/2,
/*mask_resource_id=*/0, gfx::RectF(), gfx::Size(),
- gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false,
- 1.0f);
+ /*mask_applies_to_backdrop=*/false, gfx::Vector2dF(1, 1),
+ gfx::PointF(), gfx::RectF(), false, 1.0f);
auto* quad2_root_2 =
pass2_root->quad_list.AllocateAndConstruct<viz::RenderPassDrawQuad>();
quad2_root_2->SetNew(shared_quad_state2_root, /*rect=*/rect2_root,
/*visible_rect=*/rect2_root, /*render_pass_id=*/3,
/*mask_resource_id=*/0, gfx::RectF(), gfx::Size(),
- gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false,
- 1.0f);
+ /*mask_applies_to_backdrop=*/false, gfx::Vector2dF(1, 1),
+ gfx::PointF(), gfx::RectF(), false, 1.0f);
pass_list.push_back(std::move(pass2_root));
SendRenderPassList(&pass_list, /*hit_test_data_changed=*/true);
diff --git a/chromium/cc/paint/BUILD.gn b/chromium/cc/paint/BUILD.gn
index 6c428fbabfa..705951c1e6b 100644
--- a/chromium/cc/paint/BUILD.gn
+++ b/chromium/cc/paint/BUILD.gn
@@ -18,6 +18,8 @@ cc_component("paint") {
"display_item_list.h",
"draw_image.cc",
"draw_image.h",
+ "element_id.cc",
+ "element_id.h",
"filter_operation.cc",
"filter_operation.h",
"filter_operations.cc",
@@ -29,8 +31,7 @@ cc_component("paint") {
"image_provider.h",
"image_transfer_cache_entry.cc",
"image_transfer_cache_entry.h",
- "node_holder.cc",
- "node_holder.h",
+ "node_id.h",
"paint_cache.cc",
"paint_cache.h",
"paint_canvas.h",
@@ -60,6 +61,8 @@ cc_component("paint") {
"paint_shader.cc",
"paint_shader.h",
"paint_worklet_input.h",
+ "paint_worklet_job.cc",
+ "paint_worklet_job.h",
"paint_worklet_layer_painter.h",
"raw_memory_transfer_cache_entry.cc",
"raw_memory_transfer_cache_entry.h",
@@ -79,7 +82,6 @@ cc_component("paint") {
"skottie_wrapper.h",
"solid_color_analyzer.cc",
"solid_color_analyzer.h",
- "text_holder.h",
"transfer_cache_deserialize_helper.h",
"transfer_cache_entry.cc",
"transfer_cache_entry.h",
diff --git a/chromium/cc/paint/DEPS b/chromium/cc/paint/DEPS
index 6d60ad8e8d6..844d096658c 100644
--- a/chromium/cc/paint/DEPS
+++ b/chromium/cc/paint/DEPS
@@ -1,4 +1,16 @@
+# cc/paint can only depends on some specific folders, so explicitly
+# write include rules here to be clear.
+include_rules = [
+ "-cc",
+ "+cc/base",
+ "+cc/debug",
+ "+cc/paint",
+]
+
specific_include_rules = {
+ ".*(test|_fuzzer)\.cc": [
+ "+cc",
+ ],
"paint_op_buffer_fuzzer.cc": [
"+components/viz/test",
"+gpu/command_buffer",
diff --git a/chromium/cc/paint/discardable_image_map.cc b/chromium/cc/paint/discardable_image_map.cc
index 23ccb20940a..fcf04a19e44 100644
--- a/chromium/cc/paint/discardable_image_map.cc
+++ b/chromium/cc/paint/discardable_image_map.cc
@@ -103,6 +103,9 @@ class DiscardableImageGenerator {
TakeAnimatedImagesMetadata() {
return std::move(animated_images_metadata_);
}
+ std::vector<scoped_refptr<PaintWorkletInput>> TakePaintWorkletInputs() {
+ return std::move(paint_worklet_inputs_);
+ }
void RecordColorHistograms() const {
if (color_stats_total_image_count_ > 0) {
@@ -354,9 +357,12 @@ class DiscardableImageGenerator {
SkIRect src_irect;
src_rect.roundOut(&src_irect);
- if (!paint_image.IsPaintWorklet()) {
+ if (paint_image.IsPaintWorklet()) {
+ paint_worklet_inputs_.push_back(paint_image.paint_worklet_input());
+ } else {
// Make a note if any image was originally specified in a non-sRGB color
- // space.
+ // space. PaintWorklets do not have the concept of a color space, so
+ // should not be used to accumulate either counter.
SkColorSpace* source_color_space = paint_image.color_space();
color_stats_total_pixel_count_ += image_rect.size().GetCheckedArea();
color_stats_total_image_count_++;
@@ -389,12 +395,20 @@ class DiscardableImageGenerator {
paint_image.reset_animation_sequence_id());
}
- // If we are iterating images in a record shader, only track them if they
- // are animated. We defer decoding of images in record shaders to skia, but
- // we still need to track animated images to invalidate and advance the
- // animation in cc.
- bool add_image =
- !only_gather_animated_images_ || paint_image.ShouldAnimate();
+ bool add_image = true;
+ if (paint_image.IsPaintWorklet()) {
+ // PaintWorklet-backed images don't go through the image decode pipeline
+ // (they are painted pre-raster from LayerTreeHostImpl), so do not need to
+ // be added to the |image_set_|.
+ add_image = false;
+ } else if (only_gather_animated_images_) {
+ // If we are iterating images in a record shader, only track them if they
+ // are animated. We defer decoding of images in record shaders to skia,
+ // but we still need to track animated images to invalidate and advance
+ // the animation in cc.
+ add_image = paint_image.ShouldAnimate();
+ }
+
if (add_image) {
image_set_.emplace_back(
DrawImage(std::move(paint_image), src_irect, filter_quality, matrix),
@@ -406,6 +420,7 @@ class DiscardableImageGenerator {
base::flat_map<PaintImage::Id, DiscardableImageMap::Rects> image_id_to_rects_;
std::vector<DiscardableImageMap::AnimatedImageMetadata>
animated_images_metadata_;
+ std::vector<scoped_refptr<PaintWorkletInput>> paint_worklet_inputs_;
base::flat_map<PaintImage::Id, PaintImage::DecodingMode> decoding_mode_map_;
bool only_gather_animated_images_ = false;
@@ -434,6 +449,7 @@ void DiscardableImageMap::Generate(const PaintOpBuffer* paint_op_buffer,
generator.RecordColorHistograms();
image_id_to_rects_ = generator.TakeImageIdToRectsMap();
animated_images_metadata_ = generator.TakeAnimatedImagesMetadata();
+ paint_worklet_inputs_ = generator.TakePaintWorkletInputs();
decoding_mode_map_ = generator.TakeDecodingModeMap();
all_images_are_srgb_ = generator.all_images_are_srgb();
auto images = generator.TakeImages();
diff --git a/chromium/cc/paint/discardable_image_map.h b/chromium/cc/paint/discardable_image_map.h
index a9d1bb96d09..dd494fa3fd6 100644
--- a/chromium/cc/paint/discardable_image_map.h
+++ b/chromium/cc/paint/discardable_image_map.h
@@ -70,6 +70,11 @@ class CC_PAINT_EXPORT DiscardableImageMap {
base::flat_map<PaintImage::Id, PaintImage::DecodingMode>
TakeDecodingModeMap();
+ const std::vector<scoped_refptr<PaintWorkletInput>>& paint_worklet_inputs()
+ const {
+ return paint_worklet_inputs_;
+ }
+
private:
friend class ScopedMetadataGenerator;
friend class DiscardableImageMapTest;
@@ -86,6 +91,8 @@ class CC_PAINT_EXPORT DiscardableImageMap {
bool all_images_are_srgb_ = false;
RTree<DrawImage> images_rtree_;
+
+ std::vector<scoped_refptr<PaintWorkletInput>> paint_worklet_inputs_;
};
} // namespace cc
diff --git a/chromium/cc/paint/discardable_image_map_unittest.cc b/chromium/cc/paint/discardable_image_map_unittest.cc
index 8e4a0734995..e7ecf7ee498 100644
--- a/chromium/cc/paint/discardable_image_map_unittest.cc
+++ b/chromium/cc/paint/discardable_image_map_unittest.cc
@@ -732,6 +732,39 @@ TEST_F(DiscardableImageMapTest, GathersAnimatedImages) {
EXPECT_DCHECK_DEATH(images[2]->frame_index());
}
+TEST_F(DiscardableImageMapTest, GathersPaintWorklets) {
+ gfx::Rect visible_rect(1000, 1000);
+ FakeContentLayerClient content_layer_client;
+ content_layer_client.set_bounds(visible_rect.size());
+
+ gfx::Size image_size(100, 100);
+ PaintImage static_image = CreateDiscardablePaintImage(image_size);
+ scoped_refptr<TestPaintWorkletInput> input =
+ base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(image_size));
+ PaintImage paint_worklet_image = CreatePaintWorkletPaintImage(input);
+
+ PaintFlags flags;
+ content_layer_client.add_draw_image(static_image, gfx::Point(0, 0), flags);
+ content_layer_client.add_draw_image(paint_worklet_image, gfx::Point(100, 100),
+ flags);
+
+ scoped_refptr<DisplayItemList> display_list =
+ content_layer_client.PaintContentsToDisplayList(
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->GenerateDiscardableImagesMetadata();
+
+ const auto& paint_worklet_inputs =
+ display_list->discardable_image_map().paint_worklet_inputs();
+ ASSERT_EQ(paint_worklet_inputs.size(), 1u);
+ EXPECT_EQ(paint_worklet_inputs[0], input);
+
+ // PaintWorklets are not considered discardable images.
+ std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect(
+ display_list->discardable_image_map(), visible_rect);
+ ASSERT_EQ(images.size(), 1u);
+ EXPECT_EQ(images[0].image, static_image);
+}
+
TEST_F(DiscardableImageMapTest, CapturesImagesInPaintRecordShaders) {
// Create the record to use in the shader.
auto shader_record = sk_make_sp<PaintOpBuffer>();
@@ -884,19 +917,6 @@ TEST_F(DiscardableImageMapTest, EmbeddedShaderWithAnimatedImages) {
ImageAnalysisState::kAnimatedImages);
}
-TEST_F(DiscardableImageMapTest, BuildPaintWorkletImage) {
- gfx::SizeF size(100, 50);
- scoped_refptr<TestPaintWorkletInput> input =
- base::MakeRefCounted<TestPaintWorkletInput>(size);
- PaintImage paint_image = PaintImageBuilder::WithDefault()
- .set_id(1)
- .set_paint_worklet_input(std::move(input))
- .TakePaintImage();
- EXPECT_TRUE(paint_image.paint_worklet_input());
- EXPECT_EQ(paint_image.width(), size.width());
- EXPECT_EQ(paint_image.height(), size.height());
-}
-
TEST_F(DiscardableImageMapTest, DecodingModeHintsBasic) {
gfx::Rect visible_rect(100, 100);
PaintImage unspecified_image =
diff --git a/chromium/cc/paint/display_item_list.cc b/chromium/cc/paint/display_item_list.cc
index c82e1d2d13f..403c58fa674 100644
--- a/chromium/cc/paint/display_item_list.cc
+++ b/chromium/cc/paint/display_item_list.cc
@@ -32,10 +32,10 @@ bool GetCanvasClipBounds(SkCanvas* canvas, gfx::Rect* clip_bounds) {
}
void FillTextContent(const PaintOpBuffer* buffer,
- std::vector<NodeHolder>* content) {
+ std::vector<NodeId>* content) {
for (auto* op : PaintOpBuffer::Iterator(buffer)) {
if (op->GetType() == PaintOpType::DrawTextBlob) {
- content->push_back(static_cast<DrawTextBlobOp*>(op)->node_holder);
+ content->push_back(static_cast<DrawTextBlobOp*>(op)->node_id);
} else if (op->GetType() == PaintOpType::DrawRecord) {
FillTextContent(static_cast<DrawRecordOp*>(op)->record.get(), content);
}
@@ -44,12 +44,12 @@ void FillTextContent(const PaintOpBuffer* buffer,
void FillTextContentByOffsets(const PaintOpBuffer* buffer,
const std::vector<size_t>& offsets,
- std::vector<NodeHolder>* content) {
+ std::vector<NodeId>* content) {
if (!buffer)
return;
for (auto* op : PaintOpBuffer::OffsetIterator(buffer, &offsets)) {
if (op->GetType() == PaintOpType::DrawTextBlob) {
- content->push_back(static_cast<DrawTextBlobOp*>(op)->node_holder);
+ content->push_back(static_cast<DrawTextBlobOp*>(op)->node_id);
} else if (op->GetType() == PaintOpType::DrawRecord) {
FillTextContent(static_cast<DrawRecordOp*>(op)->record.get(), content);
}
@@ -82,7 +82,7 @@ void DisplayItemList::Raster(SkCanvas* canvas,
}
void DisplayItemList::CaptureContent(const gfx::Rect& rect,
- std::vector<NodeHolder>* content) const {
+ std::vector<NodeId>* content) const {
std::vector<size_t> offsets;
rtree_.Search(rect, &offsets);
FillTextContentByOffsets(&paint_op_buffer_, offsets, content);
diff --git a/chromium/cc/paint/display_item_list.h b/chromium/cc/paint/display_item_list.h
index d11f49ad6a1..af922d371b7 100644
--- a/chromium/cc/paint/display_item_list.h
+++ b/chromium/cc/paint/display_item_list.h
@@ -63,9 +63,9 @@ class CC_PAINT_EXPORT DisplayItemList
void Raster(SkCanvas* canvas, ImageProvider* image_provider = nullptr) const;
// Captures the DrawTextBlobOp within |rect| and returns the associated
- // NodeHolder in |content|.
+ // NodeId in |content|.
void CaptureContent(const gfx::Rect& rect,
- std::vector<NodeHolder>* content) const;
+ std::vector<NodeId>* content) const;
void StartPaint() {
#if DCHECK_IS_ON()
@@ -165,6 +165,7 @@ class CC_PAINT_EXPORT DisplayItemList
int NumSlowPaths() const { return paint_op_buffer_.numSlowPaths(); }
bool HasNonAAPaint() const { return paint_op_buffer_.HasNonAAPaint(); }
+ bool HasText() const { return paint_op_buffer_.HasText(); }
// This gives the total number of PaintOps.
size_t TotalOpCount() const { return paint_op_buffer_.total_op_count(); }
diff --git a/chromium/cc/trees/element_id.cc b/chromium/cc/paint/element_id.cc
index 6690378fc16..15d78835bca 100644
--- a/chromium/cc/trees/element_id.cc
+++ b/chromium/cc/paint/element_id.cc
@@ -1,8 +1,8 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2019 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/element_id.h"
+#include "cc/paint/element_id.h"
#include <inttypes.h>
#include <limits>
diff --git a/chromium/cc/trees/element_id.h b/chromium/cc/paint/element_id.h
index e8275c521cc..59e01582126 100644
--- a/chromium/cc/trees/element_id.h
+++ b/chromium/cc/paint/element_id.h
@@ -1,9 +1,9 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2019 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.
-#ifndef CC_TREES_ELEMENT_ID_H_
-#define CC_TREES_ELEMENT_ID_H_
+#ifndef CC_PAINT_ELEMENT_ID_H_
+#define CC_PAINT_ELEMENT_ID_H_
#include <stddef.h>
@@ -13,7 +13,7 @@
#include <memory>
#include "base/hash/hash.h"
-#include "cc/cc_export.h"
+#include "cc/paint/paint_export.h"
namespace base {
class Value;
@@ -44,7 +44,7 @@ using ElementIdType = uint64_t;
// to the layer tree and uses element ids as a stable identifier for animation
// targets. A Layer's element id can change over the Layer's lifetime because
// non-default ElementIds are only set during an animation's lifetime.
-struct CC_EXPORT ElementId {
+struct CC_PAINT_EXPORT ElementId {
explicit ElementId(ElementIdType id) : id_(id) {
DCHECK_NE(id, kInvalidElementId);
}
@@ -75,15 +75,16 @@ struct CC_EXPORT ElementId {
ElementIdType id_;
};
-ElementId CC_EXPORT LayerIdToElementIdForTesting(int layer_id);
+ElementId CC_PAINT_EXPORT LayerIdToElementIdForTesting(int layer_id);
-struct CC_EXPORT ElementIdHash {
+struct CC_PAINT_EXPORT ElementIdHash {
size_t operator()(ElementId key) const;
};
// Stream operator so ElementId can be used in assertion statements.
-CC_EXPORT std::ostream& operator<<(std::ostream& out, const ElementId& id);
+CC_PAINT_EXPORT std::ostream& operator<<(std::ostream& out,
+ const ElementId& id);
} // namespace cc
-#endif // CC_TREES_ELEMENT_ID_H_
+#endif // CC_PAINT_ELEMENT_ID_H_
diff --git a/chromium/cc/paint/image_provider.cc b/chromium/cc/paint/image_provider.cc
index e30c8bb5e7d..dd471cbfdf6 100644
--- a/chromium/cc/paint/image_provider.cc
+++ b/chromium/cc/paint/image_provider.cc
@@ -13,16 +13,13 @@ ImageProvider::ScopedResult::ScopedResult() = default;
ImageProvider::ScopedResult::ScopedResult(DecodedDrawImage image)
: image_(std::move(image)) {}
+ImageProvider::ScopedResult::ScopedResult(sk_sp<PaintRecord> record)
+ : record_(std::move(record)) {}
+
ImageProvider::ScopedResult::ScopedResult(DecodedDrawImage image,
DestructionCallback callback)
: image_(std::move(image)), destruction_callback_(std::move(callback)) {}
-ImageProvider::ScopedResult::ScopedResult(sk_sp<PaintRecord> record,
- DestructionCallback callback)
- : record_(std::move(record)), destruction_callback_(std::move(callback)) {
- DCHECK(!destruction_callback_.is_null());
-}
-
ImageProvider::ScopedResult::ScopedResult(ScopedResult&& other)
: image_(std::move(other.image_)),
record_(std::move(other.record_)),
diff --git a/chromium/cc/paint/image_provider.h b/chromium/cc/paint/image_provider.h
index 2b5e5f70713..973f8f78a9d 100644
--- a/chromium/cc/paint/image_provider.h
+++ b/chromium/cc/paint/image_provider.h
@@ -27,8 +27,8 @@ class CC_PAINT_EXPORT ImageProvider {
ScopedResult();
explicit ScopedResult(DecodedDrawImage image);
+ explicit ScopedResult(sk_sp<PaintRecord> record);
ScopedResult(DecodedDrawImage image, DestructionCallback callback);
- ScopedResult(sk_sp<PaintRecord> record, DestructionCallback callback);
ScopedResult(const ScopedResult&) = delete;
ScopedResult(ScopedResult&& other);
~ScopedResult();
diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc
index 9e96fdbc3a3..964f5321c23 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.cc
+++ b/chromium/cc/paint/image_transfer_cache_entry.cc
@@ -4,11 +4,14 @@
#include "cc/paint/image_transfer_cache_entry.h"
+#include <array>
+#include <type_traits>
#include <utility>
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/numerics/checked_math.h"
+#include "base/numerics/safe_conversions.h"
#include "cc/paint/paint_op_reader.h"
#include "cc/paint/paint_op_writer.h"
#include "third_party/skia/include/core/SkColorSpace.h"
@@ -23,6 +26,74 @@
namespace cc {
namespace {
+// Creates a SkImage backed by the YUV textures corresponding to |plane_images|.
+// The layout is specified by |plane_images_format|). The backend textures are
+// first extracted out of the |plane_images| (and work is flushed on each one).
+// Note that we assume that the image is opaque (no alpha plane). Then, a
+// SkImage is created out of those textures using the
+// SkImage::MakeFromYUVATextures() API. Finally, |image_color_space| is the
+// color space of the resulting image after applying |yuv_color_space|
+// (converting from YUV to RGB). This is assumed to be sRGB if nullptr.
+//
+// On success, the resulting SkImage is
+// returned. On failure, nullptr is returned (e.g., if one of the backend
+// textures is invalid or a Skia error occurs).
+sk_sp<SkImage> MakeYUVImageFromUploadedPlanes(
+ GrContext* context,
+ const std::vector<sk_sp<SkImage>>& plane_images,
+ YUVDecodeFormat plane_images_format,
+ SkYUVColorSpace yuv_color_space,
+ sk_sp<SkColorSpace> image_color_space) {
+ // 1) Extract the textures.
+ DCHECK_NE(YUVDecodeFormat::kUnknown, plane_images_format);
+ DCHECK_EQ(NumberOfPlanesForYUVDecodeFormat(plane_images_format),
+ plane_images.size());
+ DCHECK_LE(plane_images.size(),
+ base::checked_cast<size_t>(SkYUVASizeInfo::kMaxCount));
+ std::array<GrBackendTexture, SkYUVASizeInfo::kMaxCount>
+ plane_backend_textures;
+ for (size_t plane = 0u; plane < plane_images.size(); plane++) {
+ plane_backend_textures[plane] = plane_images[plane]->getBackendTexture(
+ true /* flushPendingGrContextIO */);
+ if (!plane_backend_textures[plane].isValid()) {
+ DLOG(ERROR) << "Invalid backend texture found";
+ return nullptr;
+ }
+ }
+
+ // 2) Create the YUV image.
+ SkYUVAIndex plane_indices[SkYUVAIndex::kIndexCount];
+ if (plane_images_format == YUVDecodeFormat::kYUV3) {
+ plane_indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
+ plane_indices[SkYUVAIndex::kU_Index] = {1, SkColorChannel::kR};
+ plane_indices[SkYUVAIndex::kV_Index] = {2, SkColorChannel::kR};
+ } else if (plane_images_format == YUVDecodeFormat::kYVU3) {
+ plane_indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
+ plane_indices[SkYUVAIndex::kU_Index] = {2, SkColorChannel::kR};
+ plane_indices[SkYUVAIndex::kV_Index] = {1, SkColorChannel::kR};
+ } else if (plane_images_format == YUVDecodeFormat::kYUV2) {
+ plane_indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
+ plane_indices[SkYUVAIndex::kU_Index] = {1, SkColorChannel::kR};
+ plane_indices[SkYUVAIndex::kV_Index] = {1, SkColorChannel::kG};
+ } else {
+ // TODO(crbug.com/910276): handle and test non-opaque images.
+ NOTREACHED();
+ DLOG(ERROR) << "Unsupported planar format";
+ return nullptr;
+ }
+ plane_indices[SkYUVAIndex::kA_Index] = {-1, SkColorChannel::kR};
+ sk_sp<SkImage> image = SkImage::MakeFromYUVATextures(
+ context, yuv_color_space, plane_backend_textures.data(), plane_indices,
+ plane_images[0]->dimensions(), kTopLeft_GrSurfaceOrigin,
+ std::move(image_color_space));
+ if (!image) {
+ DLOG(ERROR) << "Could not create YUV image";
+ return nullptr;
+ }
+
+ return image;
+}
+
// TODO(ericrk): Replace calls to this with calls to SkImage::makeTextureImage,
// once that function handles colorspaces. https://crbug.com/834837
sk_sp<SkImage> MakeTextureImage(GrContext* context,
@@ -63,30 +134,50 @@ sk_sp<SkImage> MakeTextureImage(GrContext* context,
} // namespace
+size_t NumberOfPlanesForYUVDecodeFormat(YUVDecodeFormat format) {
+ switch (format) {
+ case YUVDecodeFormat::kYUVA4:
+ return 4u;
+ case YUVDecodeFormat::kYUV3:
+ case YUVDecodeFormat::kYVU3:
+ return 3u;
+ case YUVDecodeFormat::kYUV2:
+ return 2u;
+ case YUVDecodeFormat::kUnknown:
+ return 0u;
+ }
+}
+
ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
const SkPixmap* pixmap,
const SkColorSpace* target_color_space,
bool needs_mips)
- : id_(s_next_id_.GetNext()),
+ : needs_mips_(needs_mips),
+ id_(GetNextId()),
pixmap_(pixmap),
target_color_space_(target_color_space),
- needs_mips_(needs_mips) {
+ decoded_color_space_(nullptr) {
size_t target_color_space_size =
target_color_space ? target_color_space->writeToMemory(nullptr) : 0u;
size_t pixmap_color_space_size =
pixmap_->colorSpace() ? pixmap_->colorSpace()->writeToMemory(nullptr)
: 0u;
+ // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte
+ // alignment. Always use 8 byte alignment.
+ const size_t align = sizeof(uint64_t);
+
// Compute and cache the size of the data.
base::CheckedNumeric<uint32_t> safe_size;
safe_size += PaintOpWriter::HeaderBytes();
+ safe_size += sizeof(uint32_t); // is_yuv
safe_size += sizeof(uint32_t); // color type
safe_size += sizeof(uint32_t); // width
safe_size += sizeof(uint32_t); // height
safe_size += sizeof(uint32_t); // has mips
- safe_size += sizeof(uint64_t) + alignof(uint64_t); // pixels size
- safe_size += target_color_space_size + sizeof(uint64_t) + alignof(uint64_t);
- safe_size += pixmap_color_space_size + sizeof(uint64_t) + alignof(uint64_t);
+ safe_size += sizeof(uint64_t) + align; // pixels size + alignment
+ safe_size += target_color_space_size + sizeof(uint64_t) + align;
+ safe_size += pixmap_color_space_size + sizeof(uint64_t) + align;
// Include 4 bytes of padding so we can always align our data pointer to a
// 4-byte boundary.
safe_size += 4;
@@ -94,6 +185,50 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
size_ = safe_size.ValueOrDie();
}
+ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
+ const SkPixmap* y_pixmap,
+ const SkPixmap* u_pixmap,
+ const SkPixmap* v_pixmap,
+ const SkColorSpace* decoded_color_space,
+ SkYUVColorSpace yuv_color_space,
+ bool needs_mips)
+ : needs_mips_(needs_mips),
+ num_planes_(3),
+ id_(GetNextId()),
+ pixmap_(nullptr),
+ target_color_space_(nullptr),
+ yuv_pixmaps_({y_pixmap, u_pixmap, v_pixmap, nullptr}),
+ decoded_color_space_(decoded_color_space),
+ yuv_color_space_(yuv_color_space) {
+ DCHECK(IsYuv());
+ size_t decoded_color_space_size =
+ decoded_color_space ? decoded_color_space->writeToMemory(nullptr) : 0u;
+
+ // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte
+ // alignment. Always use 8 byte alignment.
+ const size_t align = sizeof(uint64_t);
+
+ // Compute and cache the size of the data.
+ base::CheckedNumeric<uint32_t> safe_size;
+ safe_size += PaintOpWriter::HeaderBytes();
+ safe_size += sizeof(uint32_t); // is_yuv
+ safe_size += sizeof(uint32_t); // num_planes
+ safe_size += sizeof(uint32_t); // has mips
+ safe_size += sizeof(uint32_t); // yuv_color_space
+ safe_size += decoded_color_space_size + align;
+ safe_size += num_planes_ * sizeof(uint64_t); // plane widths
+ safe_size += num_planes_ * sizeof(uint64_t); // plane heights
+ safe_size +=
+ num_planes_ * (sizeof(uint64_t) + align); // pixels size + alignment
+ // Include 4 bytes of padding before each plane data chunk so we can always
+ // align our data pointer to a 4-byte boundary.
+ safe_size += 4 * num_planes_;
+ safe_size += y_pixmap->computeByteSize();
+ safe_size += u_pixmap->computeByteSize();
+ safe_size += v_pixmap->computeByteSize();
+ size_ = safe_size.ValueOrDie();
+}
+
ClientImageTransferCacheEntry::~ClientImageTransferCacheEntry() = default;
// static
@@ -107,21 +242,64 @@ uint32_t ClientImageTransferCacheEntry::Id() const {
return id_;
}
+void ClientImageTransferCacheEntry::ValidateYUVDataBeforeSerializing() const {
+ DCHECK(!pixmap_);
+ DCHECK_LE(yuv_pixmaps_->size(),
+ static_cast<uint32_t>(SkYUVASizeInfo::kMaxCount));
+ for (uint32_t i = 0; i < num_planes_; ++i) {
+ DCHECK(yuv_pixmaps_->at(i));
+ const SkPixmap* plane = yuv_pixmaps_->at(i);
+ DCHECK_GT(plane->width(), 0);
+ DCHECK_GT(plane->height(), 0);
+ }
+ DCHECK(yuv_color_space_);
+}
+
bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const {
DCHECK_GE(data.size(), SerializedSize());
- DCHECK_GT(pixmap_->width(), 0);
- DCHECK_GT(pixmap_->height(), 0);
-
// We don't need to populate the SerializeOptions here since the writer is
// only used for serializing primitives.
PaintOp::SerializeOptions options(nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, false, false, 0, 0, SkMatrix::I());
PaintOpWriter writer(data.data(), data.size(), options);
+ writer.Write(static_cast<uint32_t>(IsYuv() ? 1 : 0));
+
+ if (IsYuv()) {
+ ValidateYUVDataBeforeSerializing();
+ writer.Write(num_planes_);
+ writer.Write(static_cast<uint32_t>(needs_mips_ ? 1 : 0));
+ writer.Write(yuv_color_space_);
+ writer.Write(decoded_color_space_);
+ for (uint32_t i = 0; i < num_planes_; ++i) {
+ DCHECK(yuv_pixmaps_->at(i));
+ const SkPixmap* plane = yuv_pixmaps_->at(i);
+ writer.Write(plane->width());
+ writer.Write(plane->height());
+ size_t plane_size = plane->computeByteSize();
+ if (plane_size == SIZE_MAX)
+ return false;
+ writer.WriteSize(plane_size);
+ writer.AlignMemory(4);
+ writer.WriteData(plane_size, plane->addr());
+ }
+
+ // Size can't be 0 after serialization unless the writer has become invalid.
+ if (writer.size() == 0u)
+ return false;
+
+ return true;
+ }
+
+ DCHECK_GT(pixmap_->width(), 0);
+ DCHECK_GT(pixmap_->height(), 0);
+
writer.Write(pixmap_->colorType());
writer.Write(pixmap_->width());
writer.Write(pixmap_->height());
writer.Write(static_cast<uint32_t>(needs_mips_ ? 1 : 0));
size_t pixmap_size = pixmap_->computeByteSize();
+ if (pixmap_size == SIZE_MAX)
+ return false;
writer.WriteSize(pixmap_size);
// TODO(enne): we should consider caching these in some form.
writer.Write(pixmap_->colorSpace());
@@ -147,61 +325,37 @@ ServiceImageTransferCacheEntry& ServiceImageTransferCacheEntry::operator=(
bool ServiceImageTransferCacheEntry::BuildFromHardwareDecodedImage(
GrContext* context,
std::vector<sk_sp<SkImage>> plane_images,
+ YUVDecodeFormat plane_images_format,
size_t buffer_byte_size,
- bool needs_mips,
- sk_sp<SkColorSpace> target_color_space) {
+ bool needs_mips) {
context_ = context;
-
- // 1) Extract the planar textures from |plane_images|.
- std::vector<GrBackendTexture> plane_backend_textures(3u);
- DCHECK_EQ(3u, plane_images.size());
- for (size_t plane = 0; plane < 3u; plane++) {
- plane_backend_textures[plane] = plane_images[plane]->getBackendTexture(
- true /* flushPendingGrContextIO */);
- if (!plane_backend_textures[plane].isValid()) {
- DLOG(ERROR) << "Invalid backend texture found";
- return false;
- }
- if (needs_mips) {
- // TODO(andrescj): generate mipmaps when requested. This will require some
- // resource management: we either let Skia own the new textures or we take
- // ownership and delete them in |destroy_callback|.
- NOTIMPLEMENTED();
+ yuv_color_space_ = SkYUVColorSpace::kJPEG_SkYUVColorSpace;
+
+ // 1) Generate mipmap chains if requested.
+ if (needs_mips) {
+ for (size_t plane = 0; plane < plane_images.size(); plane++) {
+ plane_images[plane] = plane_images[plane]->makeTextureImage(
+ context_, nullptr /* dstColorSpace */, GrMipMapped::kYes);
+ if (!plane_images[plane]) {
+ DLOG(ERROR) << "Could not generate mipmap chain for plane " << plane;
+ return false;
+ }
}
}
plane_images_ = std::move(plane_images);
-
- // 2) Create a SkImage backed by the YUV textures extracted above. There are
- // two assumptions here:
- //
- // - SkYUVColorSpace::kJPEG_SkYUVColorSpace is used for the YUV-to-RGB
- // matrix.
- // - The color space of the resulting image is sRGB.
- //
- // TODO(andrescj): support other YUV-to-RGB conversions and embedded color
- // profiles.
- SkYUVAIndex plane_indices[] = {
- SkYUVAIndex{0, SkColorChannel::kR}, SkYUVAIndex{1, SkColorChannel::kR},
- SkYUVAIndex{2, SkColorChannel::kR}, SkYUVAIndex{-1, SkColorChannel::kR}};
- image_ = SkImage::MakeFromYUVATextures(
- context_, SkYUVColorSpace::kJPEG_SkYUVColorSpace,
- plane_backend_textures.data(), plane_indices,
- plane_images_[0]->dimensions(), kTopLeft_GrSurfaceOrigin);
- if (!image_) {
- DLOG(ERROR) << "Could not create YUV SkImage";
- return false;
- }
-
- // 3) Perform color space conversion if necessary.
- if (target_color_space)
- image_ = image_->makeColorSpace(target_color_space);
- if (!image_) {
- DLOG(ERROR) << "Could not do color space conversion";
+ plane_images_format_ = plane_images_format;
+
+ // 2) Create a SkImage backed by |plane_images|.
+ // TODO(andrescj): support embedded color profiles for hardware decodes and
+ // pass the color space to MakeYUVImageFromUploadedPlanes.
+ image_ = MakeYUVImageFromUploadedPlanes(
+ context_, plane_images_, plane_images_format_, yuv_color_space_,
+ SkColorSpace::MakeSRGB());
+ if (!image_)
return false;
- }
- // 4) Fill out the rest of the information.
- has_mips_ = false;
+ // 3) Fill out the rest of the information.
+ has_mips_ = needs_mips;
size_ = buffer_byte_size;
fits_on_gpu_ = true;
return true;
@@ -222,6 +376,91 @@ bool ServiceImageTransferCacheEntry::Deserialize(
PaintOp::DeserializeOptions options(nullptr, nullptr, nullptr,
&scratch_buffer);
PaintOpReader reader(data.data(), data.size(), options);
+ uint32_t image_is_yuv;
+ reader.Read(&image_is_yuv);
+ if (!!image_is_yuv) {
+ uint32_t num_planes;
+ reader.Read(&num_planes);
+ // YUV or YUVA
+ // TODO(crbug.com/986575): consider serializing a YUVDecodeFormat.
+ if (num_planes != 3u && num_planes != 4u)
+ return false;
+ plane_images_format_ =
+ num_planes == 3u ? YUVDecodeFormat::kYUV3 : YUVDecodeFormat::kYUVA4;
+ uint32_t needs_mips;
+ reader.Read(&needs_mips);
+ has_mips_ = needs_mips;
+ SkYUVColorSpace yuv_color_space;
+ reader.Read(&yuv_color_space);
+ yuv_color_space_ = yuv_color_space;
+ sk_sp<SkColorSpace> decoded_color_space;
+ reader.Read(&decoded_color_space);
+
+ // Match GrTexture::onGpuMemorySize so that memory traces agree.
+ auto gr_mips = has_mips_ ? GrMipMapped::kYes : GrMipMapped::kNo;
+ // Read in each plane and reconstruct pixmaps.
+ for (uint32_t i = 0; i < num_planes; i++) {
+ uint32_t plane_width;
+ reader.Read(&plane_width);
+ uint32_t plane_height;
+ reader.Read(&plane_height);
+ // Because Skia does not support YUV rasterization from software planes,
+ // we require that each pixmap fits in a GPU texture. In the
+ // GpuImageDecodeCache, we veto YUV decoding if the planes would be too
+ // big.
+ uint32_t max_size = static_cast<uint32_t>(context_->maxTextureSize());
+ // We compute this for each plane in case a malicious renderer tries to
+ // send very large U or V planes.
+ fits_on_gpu_ = plane_width <= max_size && plane_height <= max_size;
+ if (!fits_on_gpu_)
+ return false;
+
+ size_t plane_bytes;
+ reader.ReadSize(&plane_bytes);
+ constexpr SkColorType yuv_plane_color_type = kGray_8_SkColorType;
+ SkImageInfo plane_pixmap_info =
+ SkImageInfo::Make(plane_width, plane_height, yuv_plane_color_type,
+ kPremul_SkAlphaType, decoded_color_space);
+ if (plane_pixmap_info.computeMinByteSize() > plane_bytes)
+ return false;
+ // Align data to a 4-byte boundary, to match what we did when writing.
+ reader.AlignMemory(4);
+ const volatile void* plane_pixel_data =
+ reader.ExtractReadableMemory(plane_bytes);
+ if (!reader.valid())
+ return false;
+ DCHECK(SkIsAlign4(reinterpret_cast<uintptr_t>(plane_pixel_data)));
+ const size_t plane_size = GrContext::ComputeTextureSize(
+ yuv_plane_color_type, plane_width, plane_height, gr_mips);
+ size_ += plane_size;
+ plane_sizes_.push_back(plane_size);
+
+ // Const-cast away the "volatile" on |pixel_data|. We specifically
+ // understand that a malicious caller may change our pixels under us, and
+ // are OK with this as the worst case scenario is visual corruption.
+ SkPixmap plane_pixmap(plane_pixmap_info,
+ const_cast<const void*>(plane_pixel_data),
+ plane_pixmap_info.minRowBytes());
+
+ // Nothing should read the colorspace of individual planes because that
+ // information is stored in image_, so we pass nullptr.
+ sk_sp<SkImage> plane =
+ MakeSkImage(plane_pixmap, plane_width, plane_height,
+ nullptr /* target_color_space */);
+ if (!plane)
+ return false;
+ DCHECK(plane->isTextureBacked());
+ // |plane_images_| must be set for use in EnsureMips(), memory dumps, and
+ // unit tests.
+ plane_images_.push_back(std::move(plane));
+ }
+
+ image_ = MakeYUVImageFromUploadedPlanes(
+ context_, plane_images_, plane_images_format_, yuv_color_space_,
+ decoded_color_space);
+ return !!image_;
+ }
+
SkColorType color_type = kUnknown_SkColorType;
reader.Read(&color_type);
@@ -272,10 +511,11 @@ bool ServiceImageTransferCacheEntry::Deserialize(
// this as the worst case scenario is visual corruption.
SkPixmap pixmap(image_info, const_cast<const void*>(pixel_data),
image_info.minRowBytes());
- return MakeSkImage(pixmap, width, height, target_color_space);
+ image_ = MakeSkImage(pixmap, width, height, target_color_space);
+ return !!image_;
}
-bool ServiceImageTransferCacheEntry::MakeSkImage(
+sk_sp<SkImage> ServiceImageTransferCacheEntry::MakeSkImage(
const SkPixmap& pixmap,
uint32_t width,
uint32_t height,
@@ -286,41 +526,74 @@ bool ServiceImageTransferCacheEntry::MakeSkImage(
// a software or GPU SkImage.
uint32_t max_size = context_->maxTextureSize();
fits_on_gpu_ = width <= max_size && height <= max_size;
+ sk_sp<SkImage> image;
if (fits_on_gpu_) {
- sk_sp<SkImage> image = SkImage::MakeFromRaster(pixmap, nullptr, nullptr);
+ image = SkImage::MakeFromRaster(pixmap, nullptr, nullptr);
if (!image)
- return false;
- image_ = MakeTextureImage(context_, std::move(image), target_color_space,
- has_mips_ ? GrMipMapped::kYes : GrMipMapped::kNo);
+ return nullptr;
+ image = MakeTextureImage(context_, std::move(image), target_color_space,
+ has_mips_ ? GrMipMapped::kYes : GrMipMapped::kNo);
} else {
sk_sp<SkImage> original =
SkImage::MakeFromRaster(pixmap, [](const void*, void*) {}, nullptr);
if (!original)
- return false;
+ return nullptr;
if (target_color_space) {
- image_ = original->makeColorSpace(target_color_space);
+ image = original->makeColorSpace(target_color_space);
// If color space conversion is a noop, use original data.
- if (image_ == original)
- image_ = SkImage::MakeRasterCopy(pixmap);
+ if (image == original)
+ image = SkImage::MakeRasterCopy(pixmap);
} else {
// No color conversion to do, use original data.
- image_ = SkImage::MakeRasterCopy(pixmap);
+ image = SkImage::MakeRasterCopy(pixmap);
}
}
- return !!image_;
+ // Make sure the GPU work to create the backing texture is issued.
+ if (image)
+ image->getBackendTexture(true /* flushPendingGrContextIO */);
+
+ return image;
+}
+
+const sk_sp<SkImage>& ServiceImageTransferCacheEntry::GetPlaneImage(
+ size_t index) const {
+ DCHECK_GE(index, 0u);
+ DCHECK_LT(index, plane_images_.size());
+ DCHECK(plane_images_.at(index));
+ return plane_images_.at(index);
}
void ServiceImageTransferCacheEntry::EnsureMips() {
if (has_mips_)
return;
- if (!plane_images_.empty()) {
- // TODO(andrescj): generate mipmaps for hardware-accelerated decodes when
- // requested. This will require some resource management: we either let Skia
- // own the new textures or we take ownership and delete them in
- // |destroy_callback_|.
- NOTIMPLEMENTED();
+ if (is_yuv()) {
+ DCHECK(image_);
+ DCHECK_LE(yuv_color_space_, SkYUVColorSpace::kLastEnum_SkYUVColorSpace);
+ DCHECK_NE(YUVDecodeFormat::kUnknown, plane_images_format_);
+ DCHECK_EQ(NumberOfPlanesForYUVDecodeFormat(plane_images_format_),
+ plane_images_.size());
+ std::vector<sk_sp<SkImage>> mipped_planes;
+ for (size_t plane = 0; plane < plane_images_.size(); plane++) {
+ DCHECK(plane_images_.at(plane));
+ sk_sp<SkImage> mipped_plane = plane_images_.at(plane)->makeTextureImage(
+ context_, nullptr /* dstColorSpace */, GrMipMapped::kYes);
+ if (!mipped_plane)
+ return;
+ mipped_planes.push_back(std::move(mipped_plane));
+ }
+ // Keeping a separate vector for the planes as mips are added means that we
+ // are consistent: either all planes have mips or none do.
+ for (size_t plane = 0; plane < mipped_planes.size(); plane++) {
+ plane_images_.at(plane) = std::move(mipped_planes.at(plane));
+ }
+ mipped_planes.clear();
+ image_ = MakeYUVImageFromUploadedPlanes(
+ context_, plane_images_, plane_images_format_, yuv_color_space_,
+ image_->refColorSpace() /* image_color_space */);
+ has_mips_ = true;
+ return;
}
has_mips_ = true;
diff --git a/chromium/cc/paint/image_transfer_cache_entry.h b/chromium/cc/paint/image_transfer_cache_entry.h
index e55a60d894f..7aa5bf82ec2 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.h
+++ b/chromium/cc/paint/image_transfer_cache_entry.h
@@ -14,6 +14,7 @@
#include "base/containers/span.h"
#include "cc/paint/transfer_cache_entry.h"
#include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/core/SkYUVASizeInfo.h"
class GrContext;
class SkColorSpace;
@@ -25,6 +26,17 @@ namespace cc {
static constexpr uint32_t kInvalidImageTransferCacheEntryId =
static_cast<uint32_t>(-1);
+enum class YUVDecodeFormat {
+ kYUV3, // e.g., YUV 4:2:0, 4:2:2, or 4:4:4 as 3 planes.
+ kYUVA4, // e.g., YUV 4:2:0 as 3 planes plus an alpha plane.
+ kYVU3, // e.g., YVU 4:2:0, 4:2:2, or 4:4:4 as 3 planes.
+ kYUV2, // e.g., YUV 4:2:0 as NV12 (2 planes).
+ kUnknown,
+ kMaxValue = kUnknown,
+};
+
+CC_PAINT_EXPORT size_t NumberOfPlanesForYUVDecodeFormat(YUVDecodeFormat format);
+
// Client/ServiceImageTransferCacheEntry implement a transfer cache entry
// for transferring image data. On the client side, this is a CPU SkPixmap,
// on the service side the image is uploaded and is a GPU SkImage.
@@ -34,6 +46,13 @@ class CC_PAINT_EXPORT ClientImageTransferCacheEntry
explicit ClientImageTransferCacheEntry(const SkPixmap* pixmap,
const SkColorSpace* target_color_space,
bool needs_mips);
+ explicit ClientImageTransferCacheEntry(
+ const SkPixmap* y_pixmap,
+ const SkPixmap* u_pixmap,
+ const SkPixmap* v_pixmap,
+ const SkColorSpace* decoded_color_space,
+ SkYUVColorSpace yuv_color_space,
+ bool needs_mips);
~ClientImageTransferCacheEntry() final;
uint32_t Id() const final;
@@ -42,13 +61,31 @@ class CC_PAINT_EXPORT ClientImageTransferCacheEntry
uint32_t SerializedSize() const final;
bool Serialize(base::span<uint8_t> data) const final;
+ static uint32_t GetNextId() { return s_next_id_.GetNext(); }
+ bool IsYuv() const { return !!yuv_pixmaps_; }
+
private:
+ const bool needs_mips_ = false;
+ const uint32_t num_planes_ = 1;
uint32_t id_;
- const SkPixmap* const pixmap_;
- const SkColorSpace* const target_color_space_;
- const bool needs_mips_;
uint32_t size_ = 0;
static base::AtomicSequenceNumber s_next_id_;
+
+ // RGBX-only members.
+ const SkPixmap* const pixmap_;
+ const SkColorSpace* const
+ target_color_space_; // Unused for YUV because Skia handles colorspaces
+ // at raster.
+
+ // YUVA-only members.
+ base::Optional<std::array<const SkPixmap*, SkYUVASizeInfo::kMaxCount>>
+ yuv_pixmaps_;
+ const SkColorSpace* const decoded_color_space_;
+ SkYUVColorSpace yuv_color_space_;
+
+ // DCHECKs that the appropriate data members are set or not set and have
+ // positive size dimensions.
+ void ValidateYUVDataBeforeSerializing() const;
};
class CC_PAINT_EXPORT ServiceImageTransferCacheEntry
@@ -64,23 +101,20 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry
// Populates this entry using the result of a hardware decode. The assumption
// is that |plane_images| are backed by textures that are in turn backed by a
// buffer (dmabuf in Chrome OS) containing the planes of the decoded image.
+ // |plane_images_format| indicates the planar layout of |plane_images|.
// |buffer_byte_size| is the size of the buffer. We assume the following:
//
- // - |plane_images| represents a YUV 4:2:0 triplanar image.
// - The backing textures don't have mipmaps. We will generate the mipmaps if
// |needs_mips| is true.
// - The conversion from YUV to RGB will be performed assuming a JPEG image.
- // - The colorspace of the resulting RGB image is sRGB. We will convert from
- // this to |target_color_space| (if non-null).
+ // - The colorspace of the resulting RGB image is sRGB.
//
// Returns true if the entry can be built, false otherwise.
- //
- // TODO(andrescj): actually generate the mipmaps when |needs_mips| is true.
bool BuildFromHardwareDecodedImage(GrContext* context,
std::vector<sk_sp<SkImage>> plane_images,
+ YUVDecodeFormat plane_images_format,
size_t buffer_byte_size,
- bool needs_mips,
- sk_sp<SkColorSpace> target_color_space);
+ bool needs_mips);
// ServiceTransferCacheEntry implementation:
size_t CachedSize() const final;
@@ -95,15 +129,26 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry
// Ensures the cached image has mips.
void EnsureMips();
+ // Used in tests and for registering each texture for memory dumps.
+ const sk_sp<SkImage>& GetPlaneImage(size_t index) const;
+ const std::vector<size_t>& GetPlaneCachedSizes() const {
+ return plane_sizes_;
+ }
+ bool is_yuv() const { return !plane_images_.empty(); }
+ size_t num_planes() const { return is_yuv() ? plane_images_.size() : 1u; }
+
private:
- bool MakeSkImage(const SkPixmap& pixmap,
- uint32_t width,
- uint32_t height,
- sk_sp<SkColorSpace> target_color_space);
+ sk_sp<SkImage> MakeSkImage(const SkPixmap& pixmap,
+ uint32_t width,
+ uint32_t height,
+ sk_sp<SkColorSpace> target_color_space);
GrContext* context_ = nullptr;
std::vector<sk_sp<SkImage>> plane_images_;
+ YUVDecodeFormat plane_images_format_ = YUVDecodeFormat::kUnknown;
+ std::vector<size_t> plane_sizes_;
sk_sp<SkImage> image_;
+ SkYUVColorSpace yuv_color_space_;
bool has_mips_ = false;
size_t size_ = 0;
bool fits_on_gpu_ = false;
diff --git a/chromium/cc/paint/image_transfer_cache_entry_unittest.cc b/chromium/cc/paint/image_transfer_cache_entry_unittest.cc
new file mode 100644
index 00000000000..87adbdfcee4
--- /dev/null
+++ b/chromium/cc/paint/image_transfer_cache_entry_unittest.cc
@@ -0,0 +1,328 @@
+// Copyright 2019 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 <stdint.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
+#include "build/build_config.h"
+#include "cc/paint/image_transfer_cache_entry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "third_party/skia/include/core/SkPixmap.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
+#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_context_egl.h"
+#include "ui/gl/gl_share_group.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/init/create_gr_gl_interface.h"
+#include "ui/gl/init/gl_factory.h"
+
+namespace cc {
+namespace {
+
+void MarkTextureAsReleased(SkImage::ReleaseContext context) {
+ auto* released = static_cast<bool*>(context);
+ DCHECK(!*released);
+ *released = true;
+}
+
+// Checks if all the pixels in |image| are |expected_color|.
+bool CheckImageIsSolidColor(const sk_sp<SkImage>& image,
+ SkColor expected_color) {
+ DCHECK_GE(image->width(), 1);
+ DCHECK_GE(image->height(), 1);
+ SkBitmap bitmap;
+ if (!bitmap.tryAllocN32Pixels(image->width(), image->height()))
+ return false;
+ SkPixmap pixmap;
+ if (!bitmap.peekPixels(&pixmap))
+ return false;
+ if (!image->readPixels(pixmap, 0 /* srcX */, 0 /* srcY */))
+ return false;
+ for (int y = 0; y < image->height(); y++) {
+ for (int x = 0; x < image->width(); x++) {
+ if (bitmap.getColor(x, y) != expected_color)
+ return false;
+ }
+ }
+ return true;
+}
+
+class ImageTransferCacheEntryTest
+ : public testing::TestWithParam<YUVDecodeFormat> {
+ public:
+ void SetUp() override {
+ // Initialize a GL GrContext for Skia.
+ surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
+ ASSERT_TRUE(surface_);
+ share_group_ = base::MakeRefCounted<gl::GLShareGroup>();
+ gl_context_ = base::MakeRefCounted<gl::GLContextEGL>(share_group_.get());
+ ASSERT_TRUE(gl_context_);
+ ASSERT_TRUE(
+ gl_context_->Initialize(surface_.get(), gl::GLContextAttribs()));
+ ASSERT_TRUE(gl_context_->MakeCurrent(surface_.get()));
+ sk_sp<GrGLInterface> interface(gl::init::CreateGrGLInterface(
+ *gl_context_->GetVersionInfo(), false /* use_version_es2 */));
+ gr_context_ = GrContext::MakeGL(std::move(interface));
+ ASSERT_TRUE(gr_context_);
+ }
+
+ // Creates the textures for a 64x64 YUV 4:2:0 image where all the samples in
+ // all planes are 255u. This corresponds to an RGB color of (255, 121, 255)
+ // assuming the JPEG YUV-to-RGB conversion formulas. Returns a list of
+ // SkImages backed by the textures. Note that the number of textures depends
+ // on the format (obtained using GetParam()). |release_flags| is set to a list
+ // of boolean flags initialized to false. Each flag corresponds to a plane (in
+ // the same order as the returned SkImages). When the texture for that plane
+ // is released by Skia, that flag will be set to true. Returns an empty vector
+ // on failure.
+ std::vector<sk_sp<SkImage>> CreateTestYUVImage(
+ std::unique_ptr<bool[]>* release_flags) {
+ std::vector<sk_sp<SkImage>> plane_images;
+ *release_flags = nullptr;
+ if (GetParam() == YUVDecodeFormat::kYUV3 ||
+ GetParam() == YUVDecodeFormat::kYVU3) {
+ *release_flags =
+ std::unique_ptr<bool[]>(new bool[3]{false, false, false});
+ plane_images = {
+ CreateSolidPlane(gr_context(), 64, 64, GL_R8_EXT, SkColors::kWhite,
+ release_flags->get()),
+ CreateSolidPlane(gr_context(), 32, 32, GL_R8_EXT, SkColors::kWhite,
+ release_flags->get() + 1),
+ CreateSolidPlane(gr_context(), 32, 32, GL_R8_EXT, SkColors::kWhite,
+ release_flags->get() + 2)};
+ } else if (GetParam() == YUVDecodeFormat::kYUV2) {
+ *release_flags = std::unique_ptr<bool[]>(new bool[2]{false, false});
+ plane_images = {
+ CreateSolidPlane(gr_context(), 64, 64, GL_R8_EXT, SkColors::kWhite,
+ release_flags->get()),
+ CreateSolidPlane(gr_context(), 32, 32, GL_RG8_EXT, SkColors::kWhite,
+ release_flags->get() + 1)};
+ } else {
+ NOTREACHED();
+ return {};
+ }
+ if (std::all_of(plane_images.cbegin(), plane_images.cend(),
+ [](sk_sp<SkImage> plane) { return !!plane; })) {
+ return plane_images;
+ }
+ return {};
+ }
+
+ void DeletePendingTextures() {
+ DCHECK(gr_context_);
+ for (const auto& texture : textures_to_free_) {
+ if (texture.isValid())
+ gr_context_->deleteBackendTexture(texture);
+ }
+ gr_context_->flush();
+ textures_to_free_.clear();
+ }
+
+ void TearDown() override {
+ DeletePendingTextures();
+ gr_context_.reset();
+ surface_->PrepareToDestroy(gl_context_->IsCurrent(surface_.get()));
+ surface_.reset();
+ gl_context_.reset();
+ share_group_.reset();
+ }
+
+ GrContext* gr_context() const { return gr_context_.get(); }
+
+ private:
+ // Uploads a texture corresponding to a single plane in a YUV image. All the
+ // samples in the plane are set to |color|. The texture is not owned by Skia:
+ // when Skia doesn't need it anymore, MarkTextureAsReleased() will be called.
+ sk_sp<SkImage> CreateSolidPlane(GrContext* gr_context,
+ int width,
+ int height,
+ GrGLenum texture_format,
+ const SkColor4f& color,
+ bool* released) {
+ GrBackendTexture allocated_texture = gr_context->createBackendTexture(
+ width, height, GrBackendFormat::MakeGL(texture_format, GL_TEXTURE_2D),
+ color, GrMipMapped::kNo, GrRenderable::kNo);
+ if (!allocated_texture.isValid())
+ return nullptr;
+ textures_to_free_.push_back(allocated_texture);
+ GrGLTextureInfo allocated_texture_info;
+ if (!allocated_texture.getGLTextureInfo(&allocated_texture_info))
+ return nullptr;
+ DCHECK_EQ(width, allocated_texture.width());
+ DCHECK_EQ(height, allocated_texture.height());
+ DCHECK(!allocated_texture.hasMipMaps());
+ DCHECK(allocated_texture_info.fTarget == GL_TEXTURE_2D);
+ if (texture_format == GL_RG8_EXT) {
+ // TODO(crbug.com/985458): using GL_RGBA8_EXT is a workaround so that we
+ // can make a SkImage out of a GL_RG8_EXT texture. Revisit this once Skia
+ // supports a corresponding SkColorType.
+ allocated_texture = GrBackendTexture(
+ width, height, GrMipMapped::kNo,
+ GrGLTextureInfo{GL_TEXTURE_2D, allocated_texture_info.fID,
+ GL_RGBA8_EXT});
+ }
+ *released = false;
+ return SkImage::MakeFromTexture(
+ gr_context, allocated_texture, kTopLeft_GrSurfaceOrigin,
+ texture_format == GL_RG8_EXT ? kRGBA_8888_SkColorType
+ : kAlpha_8_SkColorType,
+ kOpaque_SkAlphaType, nullptr /* colorSpace */, MarkTextureAsReleased,
+ released);
+ }
+
+ std::vector<GrBackendTexture> textures_to_free_;
+ scoped_refptr<gl::GLSurface> surface_;
+ scoped_refptr<gl::GLShareGroup> share_group_;
+ scoped_refptr<gl::GLContext> gl_context_;
+ sk_sp<GrContext> gr_context_;
+};
+
+TEST_P(ImageTransferCacheEntryTest, HardwareDecodedNoMipsAtCreation) {
+ std::unique_ptr<bool[]> release_flags;
+ std::vector<sk_sp<SkImage>> plane_images = CreateTestYUVImage(&release_flags);
+ ASSERT_EQ(NumberOfPlanesForYUVDecodeFormat(GetParam()), plane_images.size());
+
+ // Create a service-side image cache entry backed by these planes and do not
+ // request generating mipmap chains. The |buffer_byte_size| is only used for
+ // accounting, so we just set it to 0u.
+ auto entry(std::make_unique<ServiceImageTransferCacheEntry>());
+ EXPECT_TRUE(entry->BuildFromHardwareDecodedImage(
+ gr_context(), std::move(plane_images),
+ GetParam() /* plane_images_format */, 0u /* buffer_byte_size */,
+ false /* needs_mips */));
+
+ // We didn't request generating mipmap chains, so the textures we created
+ // above should stay alive until after the cache entry is deleted.
+ EXPECT_TRUE(std::none_of(release_flags.get(),
+ release_flags.get() + plane_images.size(),
+ [](bool released) { return released; }));
+ entry.reset();
+ EXPECT_TRUE(std::all_of(release_flags.get(),
+ release_flags.get() + plane_images.size(),
+ [](bool released) { return released; }));
+}
+
+TEST_P(ImageTransferCacheEntryTest, HardwareDecodedMipsAtCreation) {
+#if defined(OS_ANDROID)
+ // TODO(crbug.com/985458): this test is failing on Android for NV12 and we
+ // don't understand why yet. Revisit this once Skia supports an RG8
+ // SkColorType.
+ if (GetParam() == YUVDecodeFormat::kYUV2)
+ return;
+#endif
+ std::unique_ptr<bool[]> release_flags;
+ std::vector<sk_sp<SkImage>> plane_images = CreateTestYUVImage(&release_flags);
+ ASSERT_EQ(NumberOfPlanesForYUVDecodeFormat(GetParam()), plane_images.size());
+
+ // Create a service-side image cache entry backed by these planes and request
+ // generating mipmap chains at creation time. The |buffer_byte_size| is only
+ // used for accounting, so we just set it to 0u.
+ auto entry(std::make_unique<ServiceImageTransferCacheEntry>());
+ EXPECT_TRUE(entry->BuildFromHardwareDecodedImage(
+ gr_context(), std::move(plane_images),
+ GetParam() /* plane_images_format */, 0u /* buffer_byte_size */,
+ true /* needs_mips */));
+
+ // We requested generating mipmap chains at creation time, so the textures we
+ // created above should be released by now.
+ EXPECT_TRUE(std::all_of(release_flags.get(),
+ release_flags.get() + plane_images.size(),
+ [](bool released) { return released; }));
+ DeletePendingTextures();
+
+ // Make sure that when we read the pixels from the YUV image, we get the
+ // correct RGB color corresponding to the planes created previously. This
+ // basically checks that after deleting the original YUV textures, the new
+ // YUV image is backed by the correct mipped planes.
+ ASSERT_TRUE(entry->image());
+ EXPECT_TRUE(
+ CheckImageIsSolidColor(entry->image(), SkColorSetRGB(255, 121, 255)));
+}
+
+TEST_P(ImageTransferCacheEntryTest, HardwareDecodedMipsAfterCreation) {
+#if defined(OS_ANDROID)
+ // TODO(crbug.com/985458): this test is failing on Android for NV12 and we
+ // don't understand why yet. Revisit this once Skia supports an RG8
+ // SkColorType.
+ if (GetParam() == YUVDecodeFormat::kYUV2)
+ return;
+#endif
+ std::unique_ptr<bool[]> release_flags;
+ std::vector<sk_sp<SkImage>> plane_images = CreateTestYUVImage(&release_flags);
+ ASSERT_EQ(NumberOfPlanesForYUVDecodeFormat(GetParam()), plane_images.size());
+
+ // Create a service-side image cache entry backed by these planes and do not
+ // request generating mipmap chains at creation time. The |buffer_byte_size|
+ // is only used for accounting, so we just set it to 0u.
+ auto entry(std::make_unique<ServiceImageTransferCacheEntry>());
+ EXPECT_TRUE(entry->BuildFromHardwareDecodedImage(
+ gr_context(), std::move(plane_images),
+ GetParam() /* plane_images_format */, 0u /* buffer_byte_size */,
+ false /* needs_mips */));
+
+ // We didn't request generating mip chains, so the textures we created above
+ // should stay alive for now.
+ EXPECT_TRUE(std::none_of(release_flags.get(),
+ release_flags.get() + plane_images.size(),
+ [](bool released) { return released; }));
+
+ // Now request generating the mip chains.
+ entry->EnsureMips();
+
+ // Now the original textures should have been released.
+ EXPECT_TRUE(std::all_of(release_flags.get(),
+ release_flags.get() + plane_images.size(),
+ [](bool released) { return released; }));
+ DeletePendingTextures();
+
+ // Make sure that when we read the pixels from the YUV image, we get the
+ // correct RGB color corresponding to the planes created previously. This
+ // basically checks that after deleting the original YUV textures, the new
+ // YUV image is backed by the correct mipped planes.
+ ASSERT_TRUE(entry->image());
+ EXPECT_TRUE(
+ CheckImageIsSolidColor(entry->image(), SkColorSetRGB(255, 121, 255)));
+}
+
+std::string TestParamToString(
+ const testing::TestParamInfo<YUVDecodeFormat>& param_info) {
+ switch (param_info.param) {
+ case YUVDecodeFormat::kYUV3:
+ return "YUV3";
+ case YUVDecodeFormat::kYVU3:
+ return "YVU3";
+ case YUVDecodeFormat::kYUV2:
+ return "YUV2";
+ default:
+ NOTREACHED();
+ return "";
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+ ImageTransferCacheEntryTest,
+ ::testing::Values(YUVDecodeFormat::kYUV3,
+ YUVDecodeFormat::kYVU3,
+ YUVDecodeFormat::kYUV2),
+ TestParamToString);
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/paint/node_holder.cc b/chromium/cc/paint/node_holder.cc
deleted file mode 100644
index 1e610134ba1..00000000000
--- a/chromium/cc/paint/node_holder.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2019 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/paint/node_holder.h"
-#include "base/no_destructor.h"
-
-namespace cc {
-
-NodeHolder::NodeHolder() : is_empty(true) {}
-
-NodeHolder::NodeHolder(scoped_refptr<TextHolder> holder)
- : text_holder(holder), type(Type::kTextHolder), is_empty(false) {}
-
-NodeHolder::NodeHolder(int id) : id(id), type(Type::kID), is_empty(false) {}
-
-NodeHolder::NodeHolder(const NodeHolder& other) {
- text_holder = other.text_holder;
- id = other.id;
- type = other.type;
- is_empty = other.is_empty;
-}
-
-NodeHolder::~NodeHolder() = default;
-
-// static
-const NodeHolder& NodeHolder::EmptyNodeHolder() {
- static const base::NoDestructor<NodeHolder> s;
- return *s;
-}
-
-bool operator==(const NodeHolder& l, const NodeHolder& r) {
- if (l.is_empty != r.is_empty) {
- return false;
- } else if (l.is_empty) {
- return true;
- } else {
- switch (l.type) {
- case NodeHolder::Type::kTextHolder:
- return l.text_holder == r.text_holder;
- case NodeHolder::Type::kID:
- return l.id == r.id;
- }
- }
-}
-
-bool operator!=(const NodeHolder& l, const NodeHolder& r) {
- return !(l == r);
-}
-
-} // namespace cc
diff --git a/chromium/cc/paint/node_holder.h b/chromium/cc/paint/node_holder.h
deleted file mode 100644
index 399d65feaaf..00000000000
--- a/chromium/cc/paint/node_holder.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef CC_PAINT_NODE_HOLDER_H_
-#define CC_PAINT_NODE_HOLDER_H_
-
-#include "base/memory/scoped_refptr.h"
-#include "cc/paint/paint_export.h"
-#include "cc/paint/text_holder.h"
-
-namespace cc {
-
-// This struct is used to hold the information of node that PaintOp associates
-// with, either the TextHolder or the Id could be set, but only one will finally
-// be supported base on the performance impact.
-// This is used for ContentCapture in blink to capture on-screen content, the
-// NodeHolder shall be set to DrawTextBlobOp when blink paints the main text
-// content of page; for ContentCapture, please refer to
-// third_party/blink/renderer/core/content_capture/README.md
-struct CC_PAINT_EXPORT NodeHolder {
- NodeHolder();
- explicit NodeHolder(scoped_refptr<TextHolder> text_holder);
- explicit NodeHolder(int id);
- NodeHolder(const NodeHolder& node_holder);
- virtual ~NodeHolder();
-
- // Returns the empty NodeHolder, shall be used for content that is not
- // considered part of the main text content of the page.
- static const NodeHolder& EmptyNodeHolder();
-
- enum class Type : bool { kTextHolder = false, kID = true };
-
- // Only valid if is_empty is false.
- scoped_refptr<TextHolder> text_holder;
- int id;
- Type type;
- bool is_empty;
-};
-
-bool operator==(const NodeHolder& l, const NodeHolder& r);
-
-bool operator!=(const NodeHolder& l, const NodeHolder& r);
-
-} // namespace cc
-
-#endif // CC_PAINT_NODE_HOLDER_H_
diff --git a/chromium/cc/paint/node_id.h b/chromium/cc/paint/node_id.h
new file mode 100644
index 00000000000..02a9d8127a9
--- /dev/null
+++ b/chromium/cc/paint/node_id.h
@@ -0,0 +1,22 @@
+// Copyright 2019 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.
+
+#ifndef CC_PAINT_NODE_ID_H_
+#define CC_PAINT_NODE_ID_H_
+
+namespace cc {
+// The NodeId is used to associate the DOM node with PaintOp, its peer in
+// blink is DOMNodeId.
+//
+// This is used for ContentCapture in blink to capture on-screen content, the
+// NodeId shall be set to DrawTextBlobOp when blink paints the main text
+// content of page; for ContentCapture, please refer to
+// third_party/blink/renderer/core/content_capture/README.md
+using NodeId = int;
+
+static const NodeId kInvalidNodeId = 0;
+
+} // namespace cc
+
+#endif // CC_PAINT_NODE_ID_H_
diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc
index 9af0e518b94..a71704a78d8 100644
--- a/chromium/cc/paint/oop_pixeltest.cc
+++ b/chromium/cc/paint/oop_pixeltest.cc
@@ -18,8 +18,8 @@
#include "cc/raster/playback_image_provider.h"
#include "cc/raster/raster_source.h"
#include "cc/test/pixel_test_utils.h"
-#include "cc/test/test_in_process_context_provider.h"
#include "cc/tiles/gpu_image_decode_cache.h"
+#include "components/viz/test/test_in_process_context_provider.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/raster_implementation.h"
@@ -78,7 +78,7 @@ class OopPixelTest : public testing::Test,
void SetUp() override {
InitializeOOPContext();
gles2_context_provider_ =
- base::MakeRefCounted<TestInProcessContextProvider>(
+ base::MakeRefCounted<viz::TestInProcessContextProvider>(
/*enable_oop_rasterization=*/false, /*support_locking=*/true);
gpu::ContextResult result = gles2_context_provider_->BindToCurrentThread();
DCHECK_EQ(result, gpu::ContextResult::kSuccess);
@@ -103,7 +103,7 @@ class OopPixelTest : public testing::Test,
oop_image_cache_.reset();
raster_context_provider_ =
- base::MakeRefCounted<TestInProcessContextProvider>(
+ base::MakeRefCounted<viz::TestInProcessContextProvider>(
/*enable_oop_rasterization=*/true, /*support_locking=*/true,
&gr_shader_cache_, &activity_flags_);
gpu::ContextResult result = raster_context_provider_->BindToCurrentThread();
@@ -153,7 +153,7 @@ class OopPixelTest : public testing::Test,
SkBitmap Raster(scoped_refptr<DisplayItemList> display_item_list,
const RasterOptions& options) {
GURL url("https://example.com/foo");
- TestInProcessContextProvider::ScopedRasterContextLock lock(
+ viz::TestInProcessContextProvider::ScopedRasterContextLock lock(
raster_context_provider_.get(), url.possibly_invalid_spec().c_str());
PlaybackImageProvider image_provider(oop_image_cache_.get(),
@@ -258,7 +258,7 @@ class OopPixelTest : public testing::Test,
SkBitmap RasterExpectedBitmap(
scoped_refptr<DisplayItemList> display_item_list,
const RasterOptions& options) {
- TestInProcessContextProvider::ScopedRasterContextLock lock(
+ viz::TestInProcessContextProvider::ScopedRasterContextLock lock(
gles2_context_provider_.get());
gles2_context_provider_->GrContext()->resetContext();
@@ -344,8 +344,8 @@ class OopPixelTest : public testing::Test,
protected:
enum { kWorkingSetSize = 64 * 1024 * 1024 };
- scoped_refptr<TestInProcessContextProvider> raster_context_provider_;
- scoped_refptr<TestInProcessContextProvider> gles2_context_provider_;
+ scoped_refptr<viz::TestInProcessContextProvider> raster_context_provider_;
+ scoped_refptr<viz::TestInProcessContextProvider> gles2_context_provider_;
std::unique_ptr<GpuImageDecodeCache> gpu_image_cache_;
std::unique_ptr<GpuImageDecodeCache> oop_image_cache_;
gl::DisableNullDrawGLBindings enable_pixel_output_;
diff --git a/chromium/cc/paint/paint_canvas.h b/chromium/cc/paint/paint_canvas.h
index 0f0c694eff1..a8201032901 100644
--- a/chromium/cc/paint/paint_canvas.h
+++ b/chromium/cc/paint/paint_canvas.h
@@ -8,6 +8,7 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "build/build_config.h"
+#include "cc/paint/node_id.h"
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_image.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -22,8 +23,6 @@ class SkottieWrapper;
class PaintFlags;
class PaintOpBuffer;
-struct NodeHolder;
-
using PaintRecord = PaintOpBuffer;
// PaintCanvas is the cc/paint wrapper of SkCanvas. It has a more restricted
@@ -165,8 +164,8 @@ class CC_PAINT_EXPORT PaintCanvas {
virtual void drawTextBlob(sk_sp<SkTextBlob> blob,
SkScalar x,
SkScalar y,
- const PaintFlags& flags,
- const NodeHolder& holder) = 0;
+ NodeId node_id,
+ const PaintFlags& flags) = 0;
// Unlike SkCanvas::drawPicture, this only plays back the PaintRecord and does
// not add an additional clip. This is closer to SkPicture::playback.
diff --git a/chromium/cc/paint/paint_flags.cc b/chromium/cc/paint/paint_flags.cc
index dcdb3c3a7f8..7e138218e96 100644
--- a/chromium/cc/paint/paint_flags.cc
+++ b/chromium/cc/paint/paint_flags.cc
@@ -129,7 +129,6 @@ SkPaint PaintFlags::ToSkPaint() const {
paint.setShader(shader_->GetSkShader());
paint.setMaskFilter(mask_filter_);
paint.setColorFilter(color_filter_);
- paint.setDrawLooper(draw_looper_);
if (image_filter_)
paint.setImageFilter(image_filter_->cached_sk_filter_);
paint.setColor(color_);
diff --git a/chromium/cc/paint/paint_flags.h b/chromium/cc/paint/paint_flags.h
index 64acb7861b4..c1f1cb5ce2f 100644
--- a/chromium/cc/paint/paint_flags.h
+++ b/chromium/cc/paint/paint_flags.h
@@ -146,8 +146,19 @@ class CC_PAINT_EXPORT PaintFlags {
bool IsSimpleOpacity() const;
bool SupportsFoldingAlpha() const;
+ // SkPaint does not support loopers, so callers of SkToPaint need
+ // to check for loopers manually (see getLooper()).
SkPaint ToSkPaint() const;
+ template <typename Proc>
+ void DrawToSk(SkCanvas* canvas, Proc proc) const {
+ SkPaint paint = ToSkPaint();
+ if (const sk_sp<SkDrawLooper>& looper = getLooper())
+ looper->apply(canvas, paint, proc);
+ else
+ proc(canvas, paint);
+ }
+
bool IsValid() const;
bool operator==(const PaintFlags& other) const;
bool operator!=(const PaintFlags& other) const { return !(*this == other); }
diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h
index 2f68f070c16..4090b7495dd 100644
--- a/chromium/cc/paint/paint_image.h
+++ b/chromium/cc/paint/paint_image.h
@@ -258,8 +258,8 @@ class CC_PAINT_EXPORT PaintImage {
sk_sp<SkImage> GetSkImageForFrame(size_t index,
GeneratorClientId client_id) const;
- PaintWorkletInput* paint_worklet_input() const {
- return paint_worklet_input_.get();
+ const scoped_refptr<PaintWorkletInput>& paint_worklet_input() const {
+ return paint_worklet_input_;
}
std::string ToString() const;
diff --git a/chromium/cc/paint/paint_image_unittest.cc b/chromium/cc/paint/paint_image_unittest.cc
index 82793a61ddd..bc1a06d80ac 100644
--- a/chromium/cc/paint/paint_image_unittest.cc
+++ b/chromium/cc/paint/paint_image_unittest.cc
@@ -8,6 +8,7 @@
#include "cc/paint/paint_image_builder.h"
#include "cc/test/fake_paint_image_generator.h"
#include "cc/test/skia_common.h"
+#include "cc/test/test_paint_worklet_input.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
@@ -156,4 +157,17 @@ TEST(PaintImageTest, DecodeToYuv420NoAlpha) {
yuv_generator->reset_frames_decoded();
}
+TEST(PaintImageTest, BuildPaintWorkletImage) {
+ gfx::SizeF size(100, 50);
+ scoped_refptr<TestPaintWorkletInput> input =
+ base::MakeRefCounted<TestPaintWorkletInput>(size);
+ PaintImage paint_image = PaintImageBuilder::WithDefault()
+ .set_id(1)
+ .set_paint_worklet_input(std::move(input))
+ .TakePaintImage();
+ EXPECT_TRUE(paint_image.paint_worklet_input());
+ EXPECT_EQ(paint_image.width(), size.width());
+ EXPECT_EQ(paint_image.height(), size.height());
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc
index 1359b6362e6..4223876fd47 100644
--- a/chromium/cc/paint/paint_op_buffer.cc
+++ b/chromium/cc/paint/paint_op_buffer.cc
@@ -45,7 +45,6 @@ SkRect AdjustSrcRectForScale(SkRect original, SkSize scale_adjustment) {
original.width() * x_scale,
original.height() * y_scale);
}
-
} // namespace
#define TYPES(M) \
@@ -1026,7 +1025,7 @@ PaintOp* DrawTextBlobOp::Deserialize(const volatile void* input,
void* output,
size_t output_size,
const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawTextBlobOp) - sizeof(NodeHolder));
+ DCHECK_GE(output_size, sizeof(DrawTextBlobOp) - sizeof(NodeId));
DrawTextBlobOp* op = new (output) DrawTextBlobOp;
PaintOpReader helper(input, input_size, options);
@@ -1199,8 +1198,9 @@ void DrawDRRectOp::RasterWithFlags(const DrawDRRectOp* op,
const PaintFlags* flags,
SkCanvas* canvas,
const PlaybackParams& params) {
- SkPaint paint = flags->ToSkPaint();
- canvas->drawDRRect(op->outer, op->inner, paint);
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawDRRect(op->outer, op->inner, p);
+ });
}
void DrawImageOp::RasterWithFlags(const DrawImageOp* op,
@@ -1316,8 +1316,9 @@ void DrawIRectOp::RasterWithFlags(const DrawIRectOp* op,
const PaintFlags* flags,
SkCanvas* canvas,
const PlaybackParams& params) {
- SkPaint paint = flags->ToSkPaint();
- canvas->drawIRect(op->rect, paint);
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawIRect(op->rect, p);
+ });
}
void DrawLineOp::RasterWithFlags(const DrawLineOp* op,
@@ -1325,23 +1326,27 @@ void DrawLineOp::RasterWithFlags(const DrawLineOp* op,
SkCanvas* canvas,
const PlaybackParams& params) {
SkPaint paint = flags->ToSkPaint();
- canvas->drawLine(op->x0, op->y0, op->x1, op->y1, paint);
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawLine(op->x0, op->y0, op->x1, op->y1, p);
+ });
}
void DrawOvalOp::RasterWithFlags(const DrawOvalOp* op,
const PaintFlags* flags,
SkCanvas* canvas,
const PlaybackParams& params) {
- SkPaint paint = flags->ToSkPaint();
- canvas->drawOval(op->oval, paint);
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawOval(op->oval, p);
+ });
}
void DrawPathOp::RasterWithFlags(const DrawPathOp* op,
const PaintFlags* flags,
SkCanvas* canvas,
const PlaybackParams& params) {
- SkPaint paint = flags->ToSkPaint();
- canvas->drawPath(op->path, paint);
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawPath(op->path, p);
+ });
}
void DrawRecordOp::Raster(const DrawRecordOp* op,
@@ -1357,16 +1362,18 @@ void DrawRectOp::RasterWithFlags(const DrawRectOp* op,
const PaintFlags* flags,
SkCanvas* canvas,
const PlaybackParams& params) {
- SkPaint paint = flags->ToSkPaint();
- canvas->drawRect(op->rect, paint);
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawRect(op->rect, p);
+ });
}
void DrawRRectOp::RasterWithFlags(const DrawRRectOp* op,
const PaintFlags* flags,
SkCanvas* canvas,
const PlaybackParams& params) {
- SkPaint paint = flags->ToSkPaint();
- canvas->drawRRect(op->rrect, paint);
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawRRect(op->rrect, p);
+ });
}
void DrawSkottieOp::Raster(const DrawSkottieOp* op,
@@ -1379,8 +1386,9 @@ void DrawTextBlobOp::RasterWithFlags(const DrawTextBlobOp* op,
const PaintFlags* flags,
SkCanvas* canvas,
const PlaybackParams& params) {
- SkPaint paint = flags->ToSkPaint();
- canvas->drawTextBlob(op->blob.get(), op->x, op->y, paint);
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawTextBlob(op->blob.get(), op->x, op->y, p);
+ });
}
void RestoreOp::Raster(const RestoreOp* op,
@@ -1779,7 +1787,7 @@ bool DrawTextBlobOp::AreEqual(const PaintOp* base_left,
return false;
if (!AreEqualEvenIfNaN(left->y, right->y))
return false;
- if (left->node_holder != right->node_holder)
+ if (left->node_id != right->node_id)
return false;
SkSerialProcs default_procs;
@@ -2203,6 +2211,10 @@ bool DrawRecordOp::HasDiscardableImages() const {
return record->HasDiscardableImages();
}
+bool DrawRecordOp::HasText() const {
+ return record->HasText();
+}
+
DrawTextBlobOp::DrawTextBlobOp() : PaintOpWithFlags(kType) {}
DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
@@ -2214,13 +2226,13 @@ DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
SkScalar x,
SkScalar y,
- const PaintFlags& flags,
- const NodeHolder& holder)
+ NodeId node_id,
+ const PaintFlags& flags)
: PaintOpWithFlags(kType, flags),
blob(std::move(blob)),
x(x),
y(y),
- node_holder(holder) {}
+ node_id(node_id) {}
DrawTextBlobOp::~DrawTextBlobOp() = default;
@@ -2240,7 +2252,9 @@ PaintOpBuffer::CompositeIterator::CompositeIterator(CompositeIterator&& other) =
default;
PaintOpBuffer::PaintOpBuffer()
- : has_non_aa_paint_(false), has_discardable_images_(false) {}
+ : has_non_aa_paint_(false),
+ has_discardable_images_(false),
+ has_text_(false) {}
PaintOpBuffer::PaintOpBuffer(PaintOpBuffer&& other) {
*this = std::move(other);
@@ -2260,6 +2274,7 @@ PaintOpBuffer& PaintOpBuffer::operator=(PaintOpBuffer&& other) {
subrecord_op_count_ = other.subrecord_op_count_;
has_non_aa_paint_ = other.has_non_aa_paint_;
has_discardable_images_ = other.has_discardable_images_;
+ has_text_ = other.has_text_;
// Make sure the other pob can destruct safely.
other.used_ = 0;
@@ -2281,6 +2296,7 @@ void PaintOpBuffer::Reset() {
subrecord_bytes_used_ = 0;
subrecord_op_count_ = 0;
has_discardable_images_ = false;
+ has_text_ = false;
}
// When |op| is a nested PaintOpBuffer, this returns the PaintOp inside
@@ -2543,6 +2559,8 @@ bool PaintOpBuffer::operator==(const PaintOpBuffer& other) const {
return false;
if (has_discardable_images_ != other.has_discardable_images_)
return false;
+ if (has_text_ != other.has_text_)
+ return false;
auto left_iter = Iterator(this);
auto right_iter = Iterator(&other);
diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h
index 943fe9c9dd5..11615ac3697 100644
--- a/chromium/cc/paint/paint_op_buffer.h
+++ b/chromium/cc/paint/paint_op_buffer.h
@@ -18,7 +18,7 @@
#include "base/memory/aligned_memory.h"
#include "base/optional.h"
#include "cc/base/math_util.h"
-#include "cc/paint/node_holder.h"
+#include "cc/paint/node_id.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_flags.h"
@@ -246,6 +246,8 @@ class CC_PAINT_EXPORT PaintOp {
bool HasDiscardableImages() const { return false; }
bool HasDiscardableImagesFromFlags() const { return false; }
+ bool HasText() const { return false; }
+
// Returns the number of bytes used by this op in referenced sub records
// and display lists. This doesn't count other objects like paths or blobs.
size_t AdditionalBytesUsed() const { return 0; }
@@ -662,6 +664,7 @@ class CC_PAINT_EXPORT DrawRecordOp final : public PaintOp {
bool HasDiscardableImages() const;
int CountSlowPaths() const;
bool HasNonAAPaint() const;
+ bool HasText() const;
HAS_SERIALIZATION_FUNCTIONS();
sk_sp<const PaintRecord> record;
@@ -741,8 +744,8 @@ class CC_PAINT_EXPORT DrawTextBlobOp final : public PaintOpWithFlags {
DrawTextBlobOp(sk_sp<SkTextBlob> blob,
SkScalar x,
SkScalar y,
- const PaintFlags& flags,
- const NodeHolder& node_holder);
+ NodeId node_id,
+ const PaintFlags& flags);
~DrawTextBlobOp();
static void RasterWithFlags(const DrawTextBlobOp* op,
const PaintFlags* flags,
@@ -750,13 +753,14 @@ class CC_PAINT_EXPORT DrawTextBlobOp final : public PaintOpWithFlags {
const PlaybackParams& params);
bool IsValid() const { return flags.IsValid(); }
static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ bool HasText() const { return true; }
HAS_SERIALIZATION_FUNCTIONS();
sk_sp<SkTextBlob> blob;
SkScalar x;
SkScalar y;
// This field isn't serialized.
- NodeHolder node_holder;
+ NodeId node_id = kInvalidNodeId;
private:
DrawTextBlobOp();
@@ -952,6 +956,7 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
int numSlowPaths() const { return num_slow_paths_; }
bool HasNonAAPaint() const { return has_non_aa_paint_; }
bool HasDiscardableImages() const { return has_discardable_images_; }
+ bool HasText() const { return has_text_; }
bool operator==(const PaintOpBuffer& other) const;
bool operator!=(const PaintOpBuffer& other) const {
@@ -1012,6 +1017,8 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
has_discardable_images_ |= op->HasDiscardableImages();
has_discardable_images_ |= op->HasDiscardableImagesFromFlags();
+ has_text_ |= (op->HasText());
+
subrecord_bytes_used_ += op->AdditionalBytesUsed();
subrecord_op_count_ += op->AdditionalOpCount();
}
@@ -1239,6 +1246,7 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
bool has_non_aa_paint_ : 1;
bool has_discardable_images_ : 1;
+ bool has_text_ : 1;
};
} // namespace cc
diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc
index f40f19a4ac6..8ccd0abb75a 100644
--- a/chromium/cc/paint/paint_op_buffer_unittest.cc
+++ b/chromium/cc/paint/paint_op_buffer_unittest.cc
@@ -2732,15 +2732,10 @@ class MockImageProvider : public ImageProvider {
~MockImageProvider() override = default;
- void DoNothing() {}
-
ImageProvider::ScopedResult GetRasterContent(
const DrawImage& draw_image) override {
- if (draw_image.paint_image().IsPaintWorklet()) {
- auto callback =
- base::BindOnce(&MockImageProvider::DoNothing, base::Unretained(this));
- return ScopedResult(record_, std::move(callback));
- }
+ if (draw_image.paint_image().IsPaintWorklet())
+ return ScopedResult(record_);
if (fail_all_decodes_)
return ImageProvider::ScopedResult();
diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc
index 6dd4d8bb6a4..749875dff9b 100644
--- a/chromium/cc/paint/paint_op_reader.cc
+++ b/chromium/cc/paint/paint_op_reader.cc
@@ -8,6 +8,7 @@
#include <algorithm>
#include "base/bits.h"
+#include "base/compiler_specific.h"
#include "base/debug/dump_without_crashing.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
@@ -236,7 +237,9 @@ void PaintOpReader::Read(SkPath* path) {
case PaintCacheEntryState::kInlined: {
size_t path_bytes = 0u;
ReadSize(&path_bytes);
- if (path_bytes > remaining_bytes_ || path_bytes == 0u)
+ if (path_bytes > remaining_bytes_)
+ SetInvalid();
+ if (path_bytes == 0u)
SetInvalid();
if (!valid_)
return;
@@ -445,7 +448,11 @@ void PaintOpReader::Read(sk_sp<SkTextBlob>* blob) {
auto* scratch = CopyScratchSpace(data_bytes);
sk_sp<SkTextBlob> deserialized_blob =
SkTextBlob::Deserialize(scratch, data_bytes, procs);
- if (!deserialized_blob || typeface_ctx.invalid_typeface) {
+ if (!deserialized_blob) {
+ SetInvalid();
+ return;
+ }
+ if (typeface_ctx.invalid_typeface) {
SetInvalid();
return;
}
@@ -611,6 +618,18 @@ void PaintOpReader::Read(SkColorType* color_type) {
*color_type = static_cast<SkColorType>(raw_color_type);
}
+void PaintOpReader::Read(SkYUVColorSpace* yuv_color_space) {
+ uint32_t raw_yuv_color_space = kIdentity_SkYUVColorSpace;
+ ReadSimple(&raw_yuv_color_space);
+
+ if (raw_yuv_color_space > kLastEnum_SkYUVColorSpace) {
+ SetInvalid();
+ return;
+ }
+
+ *yuv_color_space = static_cast<SkYUVColorSpace>(raw_yuv_color_space);
+}
+
void PaintOpReader::AlignMemory(size_t alignment) {
// Due to the math below, alignment must be a power of two.
DCHECK_GT(alignment, 0u);
@@ -629,7 +648,8 @@ void PaintOpReader::AlignMemory(size_t alignment) {
remaining_bytes_ -= padding;
}
-inline void PaintOpReader::SetInvalid() {
+// Don't inline this function so that crash reports can show the caller.
+NOINLINE void PaintOpReader::SetInvalid() {
if (valid_ && options_.crash_dump_on_failure && base::RandInt(1, 10) == 1) {
base::debug::DumpWithoutCrashing();
}
diff --git a/chromium/cc/paint/paint_op_reader.h b/chromium/cc/paint/paint_op_reader.h
index e3ed7b86052..d6a7a821a6f 100644
--- a/chromium/cc/paint/paint_op_reader.h
+++ b/chromium/cc/paint/paint_op_reader.h
@@ -67,6 +67,7 @@ class CC_PAINT_EXPORT PaintOpReader {
void Read(SkColorType* color_type);
void Read(SkImageInfo* info);
void Read(sk_sp<SkColorSpace>* color_space);
+ void Read(SkYUVColorSpace* yuv_color_space);
void Read(SkClipOp* op) {
uint8_t value = 0u;
diff --git a/chromium/cc/paint/paint_op_writer.cc b/chromium/cc/paint/paint_op_writer.cc
index e94efb08399..d9bf6fc97e2 100644
--- a/chromium/cc/paint/paint_op_writer.cc
+++ b/chromium/cc/paint/paint_op_writer.cc
@@ -39,7 +39,7 @@ SkIRect MakeSrcRect(const PaintImage& image) {
size_t PaintOpWriter::GetFlattenableSize(const SkFlattenable* flattenable) {
// The first bit is always written to indicate the serialized size of the
// flattenable, or zero if it doesn't exist.
- size_t total_size = sizeof(uint64_t) + alignof(uint64_t);
+ size_t total_size = sizeof(uint64_t) + sizeof(uint64_t) /* alignment */;
if (!flattenable)
return total_size;
@@ -60,7 +60,7 @@ size_t PaintOpWriter::GetImageSize(const PaintImage& image) {
image_size += sizeof(info.colorType());
image_size += sizeof(info.width());
image_size += sizeof(info.height());
- image_size += sizeof(uint64_t) + alignof(uint64_t);
+ image_size += sizeof(uint64_t) + sizeof(uint64_t) /* alignment */;
image_size += info.computeMinByteSize();
}
return image_size;
@@ -466,6 +466,10 @@ void PaintOpWriter::Write(SkColorType color_type) {
WriteSimple(static_cast<uint32_t>(color_type));
}
+void PaintOpWriter::Write(SkYUVColorSpace yuv_color_space) {
+ WriteSimple(static_cast<uint32_t>(yuv_color_space));
+}
+
void PaintOpWriter::WriteData(size_t bytes, const void* input) {
EnsureBytes(bytes);
if (!valid_)
diff --git a/chromium/cc/paint/paint_op_writer.h b/chromium/cc/paint/paint_op_writer.h
index 2b7121c181b..af798ea1a03 100644
--- a/chromium/cc/paint/paint_op_writer.h
+++ b/chromium/cc/paint/paint_op_writer.h
@@ -11,6 +11,7 @@
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_filter.h"
#include "cc/paint/paint_op_buffer_serializer.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
struct SkRect;
struct SkIRect;
@@ -62,6 +63,7 @@ class CC_PAINT_EXPORT PaintOpWriter {
void Write(const PaintFilter* filter);
void Write(const sk_sp<SkTextBlob>& blob);
void Write(SkColorType color_type);
+ void Write(SkYUVColorSpace yuv_color_space);
void Write(SkClipOp op) { Write(static_cast<uint8_t>(op)); }
void Write(PaintCanvas::AnnotationType type) {
diff --git a/chromium/cc/paint/paint_worklet_input.h b/chromium/cc/paint/paint_worklet_input.h
index 94e2cfda4d0..c54238dabb7 100644
--- a/chromium/cc/paint/paint_worklet_input.h
+++ b/chromium/cc/paint/paint_worklet_input.h
@@ -5,13 +5,18 @@
#ifndef CC_PAINT_PAINT_WORKLET_INPUT_H_
#define CC_PAINT_PAINT_WORKLET_INPUT_H_
+#include "base/containers/flat_map.h"
#include "base/memory/ref_counted.h"
-#include "cc/cc_export.h"
+#include "cc/paint/paint_export.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/gfx/geometry/size_f.h"
namespace cc {
-class CC_EXPORT PaintWorkletInput
+class PaintOpBuffer;
+using PaintRecord = PaintOpBuffer;
+
+class CC_PAINT_EXPORT PaintWorkletInput
: public base::RefCountedThreadSafe<PaintWorkletInput> {
public:
virtual gfx::SizeF GetSize() const = 0;
@@ -22,6 +27,11 @@ class CC_EXPORT PaintWorkletInput
virtual ~PaintWorkletInput() = default;
};
+// PaintWorkletRecordMap ties the input for a PaintWorklet (PaintWorkletInput)
+// to the painted output (a PaintRecord).
+using PaintWorkletRecordMap =
+ base::flat_map<scoped_refptr<PaintWorkletInput>, sk_sp<PaintRecord>>;
+
} // namespace cc
#endif // CC_PAINT_PAINT_WORKLET_INPUT_H_
diff --git a/chromium/cc/paint/paint_worklet_job.cc b/chromium/cc/paint/paint_worklet_job.cc
new file mode 100644
index 00000000000..e339853ee76
--- /dev/null
+++ b/chromium/cc/paint/paint_worklet_job.cc
@@ -0,0 +1,24 @@
+// Copyright 2019 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/paint/paint_worklet_job.h"
+
+#include "cc/paint/paint_worklet_input.h"
+
+namespace cc {
+
+PaintWorkletJob::PaintWorkletJob(int layer_id,
+ scoped_refptr<PaintWorkletInput> input)
+ : layer_id_(layer_id), input_(std::move(input)) {}
+
+PaintWorkletJob::PaintWorkletJob(const PaintWorkletJob& other) = default;
+PaintWorkletJob::PaintWorkletJob(PaintWorkletJob&& other) = default;
+PaintWorkletJob::~PaintWorkletJob() = default;
+
+void PaintWorkletJob::SetOutput(sk_sp<PaintRecord> output) {
+ DCHECK(!output_);
+ output_ = std::move(output);
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_worklet_job.h b/chromium/cc/paint/paint_worklet_job.h
new file mode 100644
index 00000000000..e6b0d8a3b07
--- /dev/null
+++ b/chromium/cc/paint/paint_worklet_job.h
@@ -0,0 +1,59 @@
+// Copyright 2019 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.
+
+#ifndef CC_PAINT_PAINT_WORKLET_JOB_H_
+#define CC_PAINT_PAINT_WORKLET_JOB_H_
+
+#include "base/containers/flat_map.h"
+#include "base/memory/scoped_refptr.h"
+#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_record.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+
+namespace cc {
+
+class PaintWorkletInput;
+
+// A PaintWorkletJob instance encapsulates the data that needs to be passed
+// around in order to dispatch PaintWorklets to the worklet thread, paint them,
+// and return the results to cc-impl.
+class CC_PAINT_EXPORT PaintWorkletJob {
+ public:
+ PaintWorkletJob(int layer_id, scoped_refptr<PaintWorkletInput> input);
+ PaintWorkletJob(const PaintWorkletJob& other);
+ PaintWorkletJob(PaintWorkletJob&& other);
+ ~PaintWorkletJob();
+
+ int layer_id() const { return layer_id_; }
+ const scoped_refptr<PaintWorkletInput>& input() const { return input_; }
+ const sk_sp<PaintRecord>& output() const { return output_; }
+
+ void SetOutput(sk_sp<PaintRecord> output);
+
+ private:
+ // The id for the layer that the PaintWorkletInput is associated with.
+ int layer_id_;
+
+ // The input for a PaintWorkletJob is encapsulated in a PaintWorkletInput
+ // instance; see class-level comments on |PaintWorkletInput| for details.
+ scoped_refptr<PaintWorkletInput> input_;
+
+ // The output for a PaintWorkletJob is a series of paint ops for the painted
+ // content, that can be passed to raster.
+ sk_sp<PaintRecord> output_;
+};
+
+// The PaintWorklet dispatcher logic passes the PaintWorkletJobVector to the
+// worklet thread during painting. To keep the structure alive on both the
+// compositor and worklet side (as technically the compositor could be town down
+// whilst the worklet is still painting), we use base::RefCountedJob for it.
+using PaintWorkletJobVector =
+ base::RefCountedData<std::vector<PaintWorkletJob>>;
+using PaintWorkletId = int;
+using PaintWorkletJobMap =
+ base::flat_map<PaintWorkletId, scoped_refptr<PaintWorkletJobVector>>;
+
+} // namespace cc
+
+#endif // CC_PAINT_PAINT_WORKLET_JOB_H_
diff --git a/chromium/cc/paint/paint_worklet_layer_painter.h b/chromium/cc/paint/paint_worklet_layer_painter.h
index 6535432bff5..4b56a60a8de 100644
--- a/chromium/cc/paint/paint_worklet_layer_painter.h
+++ b/chromium/cc/paint/paint_worklet_layer_painter.h
@@ -5,18 +5,32 @@
#ifndef CC_PAINT_PAINT_WORKLET_LAYER_PAINTER_H_
#define CC_PAINT_PAINT_WORKLET_LAYER_PAINTER_H_
-#include "cc/cc_export.h"
+#include "base/callback.h"
+#include "cc/paint/paint_export.h"
#include "cc/paint/paint_record.h"
+#include "cc/paint/paint_worklet_job.h"
namespace cc {
-class PaintWorkletInput;
-
-class CC_EXPORT PaintWorkletLayerPainter {
+// PaintWorkletLayerPainter bridges between the compositor and the PaintWorklet
+// thread, providing hooks for the compositor to paint PaintWorklet content that
+// Blink has deferred on.
+class CC_PAINT_EXPORT PaintWorkletLayerPainter {
public:
virtual ~PaintWorkletLayerPainter() {}
- virtual sk_sp<PaintRecord> Paint(PaintWorkletInput*) = 0;
+ // Asynchronously paints a set of PaintWorklet instances. The results are
+ // returned via the provided callback, on the same thread that originally
+ // called this method.
+ //
+ // Only one dispatch is allowed at a time; the calling code should not call
+ // |DispatchWorklets| again until the passed |DoneCallback| has been called.
+ using DoneCallback = base::OnceCallback<void(PaintWorkletJobMap)>;
+ virtual void DispatchWorklets(PaintWorkletJobMap, DoneCallback) = 0;
+
+ // Returns whether or not a dispatched set of PaintWorklet instances is
+ // currently being painted.
+ virtual bool HasOngoingDispatch() const = 0;
};
} // namespace cc
diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc
index b0277f51a5b..3b1c6108092 100644
--- a/chromium/cc/paint/record_paint_canvas.cc
+++ b/chromium/cc/paint/record_paint_canvas.cc
@@ -274,9 +274,9 @@ void RecordPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
void RecordPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
SkScalar x,
SkScalar y,
- const PaintFlags& flags,
- const NodeHolder& holder) {
- list_->push<DrawTextBlobOp>(std::move(blob), x, y, flags, holder);
+ NodeId node_id,
+ const PaintFlags& flags) {
+ list_->push<DrawTextBlobOp>(std::move(blob), x, y, node_id, flags);
}
void RecordPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) {
diff --git a/chromium/cc/paint/record_paint_canvas.h b/chromium/cc/paint/record_paint_canvas.h
index c32547f2810..68ad78ab315 100644
--- a/chromium/cc/paint/record_paint_canvas.h
+++ b/chromium/cc/paint/record_paint_canvas.h
@@ -92,8 +92,8 @@ class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas {
void drawTextBlob(sk_sp<SkTextBlob> blob,
SkScalar x,
SkScalar y,
- const PaintFlags& flags,
- const NodeHolder& holder) override;
+ NodeId node_id,
+ const PaintFlags& flags) override;
void drawPicture(sk_sp<const PaintRecord> record) override;
diff --git a/chromium/cc/paint/skia_paint_canvas.cc b/chromium/cc/paint/skia_paint_canvas.cc
index 45e6e8fd6a0..3a6dfbbf907 100644
--- a/chromium/cc/paint/skia_paint_canvas.cc
+++ b/chromium/cc/paint/skia_paint_canvas.cc
@@ -11,7 +11,6 @@
#include "third_party/skia/include/core/SkAnnotation.h"
namespace cc {
-
SkiaPaintCanvas::ContextFlushes::ContextFlushes()
: enable(false), max_draws_before_flush(-1) {}
@@ -142,9 +141,11 @@ void SkiaPaintCanvas::drawLine(SkScalar x0,
255u);
if (!raster_flags.flags())
return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
- SkiaPaintCanvas::canvas_->drawLine(x0, y0, x1, y1, paint);
+ raster_flags.flags()->DrawToSk(
+ canvas_, [x0, y0, x1, y1](SkCanvas* c, const SkPaint& p) {
+ c->drawLine(x0, y0, x1, y1, p);
+ });
FlushAfterDrawIfNeeded();
}
@@ -154,9 +155,9 @@ void SkiaPaintCanvas::drawRect(const SkRect& rect, const PaintFlags& flags) {
255u);
if (!raster_flags.flags())
return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
-
- canvas_->drawRect(rect, paint);
+ raster_flags.flags()->DrawToSk(
+ canvas_,
+ [&rect](SkCanvas* c, const SkPaint& p) { c->drawRect(rect, p); });
FlushAfterDrawIfNeeded();
}
@@ -166,9 +167,9 @@ void SkiaPaintCanvas::drawIRect(const SkIRect& rect, const PaintFlags& flags) {
255u);
if (!raster_flags.flags())
return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
-
- canvas_->drawIRect(rect, paint);
+ raster_flags.flags()->DrawToSk(
+ canvas_,
+ [&rect](SkCanvas* c, const SkPaint& p) { c->drawIRect(rect, p); });
FlushAfterDrawIfNeeded();
}
@@ -178,9 +179,9 @@ void SkiaPaintCanvas::drawOval(const SkRect& oval, const PaintFlags& flags) {
255u);
if (!raster_flags.flags())
return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
-
- canvas_->drawOval(oval, paint);
+ raster_flags.flags()->DrawToSk(
+ canvas_,
+ [&oval](SkCanvas* c, const SkPaint& p) { c->drawOval(oval, p); });
FlushAfterDrawIfNeeded();
}
@@ -190,9 +191,9 @@ void SkiaPaintCanvas::drawRRect(const SkRRect& rrect, const PaintFlags& flags) {
255u);
if (!raster_flags.flags())
return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
-
- canvas_->drawRRect(rrect, paint);
+ raster_flags.flags()->DrawToSk(
+ canvas_,
+ [&rrect](SkCanvas* c, const SkPaint& p) { c->drawRRect(rrect, p); });
FlushAfterDrawIfNeeded();
}
@@ -204,9 +205,10 @@ void SkiaPaintCanvas::drawDRRect(const SkRRect& outer,
255u);
if (!raster_flags.flags())
return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
-
- canvas_->drawDRRect(outer, inner, paint);
+ raster_flags.flags()->DrawToSk(
+ canvas_, [&outer, &inner](SkCanvas* c, const SkPaint& p) {
+ c->drawDRRect(outer, inner, p);
+ });
FlushAfterDrawIfNeeded();
}
@@ -219,9 +221,10 @@ void SkiaPaintCanvas::drawRoundRect(const SkRect& rect,
255u);
if (!raster_flags.flags())
return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
-
- canvas_->drawRoundRect(rect, rx, ry, paint);
+ raster_flags.flags()->DrawToSk(
+ canvas_, [&rect, rx, ry](SkCanvas* c, const SkPaint& p) {
+ c->drawRoundRect(rect, rx, ry, p);
+ });
FlushAfterDrawIfNeeded();
}
@@ -231,9 +234,9 @@ void SkiaPaintCanvas::drawPath(const SkPath& path, const PaintFlags& flags) {
255u);
if (!raster_flags.flags())
return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
-
- canvas_->drawPath(path, paint);
+ raster_flags.flags()->DrawToSk(
+ canvas_,
+ [&path](SkCanvas* c, const SkPaint& p) { c->drawPath(path, p); });
FlushAfterDrawIfNeeded();
}
@@ -293,16 +296,18 @@ void SkiaPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
255u);
if (!raster_flags.flags())
return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
- canvas_->drawTextBlob(blob, x, y, paint);
+ raster_flags.flags()->DrawToSk(canvas_,
+ [&blob, x, y](SkCanvas* c, const SkPaint& p) {
+ c->drawTextBlob(blob, x, y, p);
+ });
FlushAfterDrawIfNeeded();
}
void SkiaPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
SkScalar x,
SkScalar y,
- const PaintFlags& flags,
- const NodeHolder& holder) {
+ NodeId node_id,
+ const PaintFlags& flags) {
drawTextBlob(blob, x, y, flags);
}
diff --git a/chromium/cc/paint/skia_paint_canvas.h b/chromium/cc/paint/skia_paint_canvas.h
index cf347d53a6e..6ba29a621d1 100644
--- a/chromium/cc/paint/skia_paint_canvas.h
+++ b/chromium/cc/paint/skia_paint_canvas.h
@@ -116,8 +116,8 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
void drawTextBlob(sk_sp<SkTextBlob> blob,
SkScalar x,
SkScalar y,
- const PaintFlags& flags,
- const NodeHolder& holder) override;
+ NodeId node_id,
+ const PaintFlags& flags) override;
void drawPicture(sk_sp<const PaintRecord> record) override;
diff --git a/chromium/cc/paint/text_holder.h b/chromium/cc/paint/text_holder.h
deleted file mode 100644
index 0bda890b060..00000000000
--- a/chromium/cc/paint/text_holder.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef CC_PAINT_TEXT_HOLDER_H_
-#define CC_PAINT_TEXT_HOLDER_H_
-
-#include <set>
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "cc/paint/paint_export.h"
-
-namespace cc {
-
-// The base class for embedder (blink) to associate DrawTextBlobOp with a text
-// node.
-// This class has to be RefCountedThreadSafe because the asscociated
-// DrawTextBlobOp could be dereferenced in main, compositor or raster worker
-// threads.
-class CC_PAINT_EXPORT TextHolder
- : public base::RefCountedThreadSafe<TextHolder> {
- protected:
- friend class base::RefCountedThreadSafe<TextHolder>;
- virtual ~TextHolder() = default;
-};
-
-} // namespace cc
-
-#endif // CC_PAINT_TEXT_HOLDER_H_
diff --git a/chromium/cc/paint/transfer_cache_unittest.cc b/chromium/cc/paint/transfer_cache_unittest.cc
index 7eb83e82dd2..19fe578ada0 100644
--- a/chromium/cc/paint/transfer_cache_unittest.cc
+++ b/chromium/cc/paint/transfer_cache_unittest.cc
@@ -10,8 +10,8 @@
#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/paint/raw_memory_transfer_cache_entry.h"
#include "cc/paint/transfer_cache_entry.h"
-#include "cc/test/test_in_process_context_provider.h"
#include "components/viz/test/test_gpu_service_holder.h"
+#include "components/viz/test/test_in_process_context_provider.h"
#include "gpu/command_buffer/client/client_transfer_cache.h"
#include "gpu/command_buffer/client/gles2_cmd_helper.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
@@ -85,7 +85,7 @@ class TransferCacheTest : public testing::Test {
private:
viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
- TestImageFactory image_factory_;
+ viz::TestImageFactory image_factory_;
std::unique_ptr<gpu::RasterInProcessContext> context_;
gl::DisableNullDrawGLBindings enable_pixel_output_;
ClientRawMemoryTransferCacheEntry test_client_entry_;
diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.cc b/chromium/cc/raster/bitmap_raster_buffer_provider.cc
index 754ff6979a0..db625272e7c 100644
--- a/chromium/cc/raster/bitmap_raster_buffer_provider.cc
+++ b/chromium/cc/raster/bitmap_raster_buffer_provider.cc
@@ -108,12 +108,11 @@ BitmapRasterBufferProvider::AcquireBufferForRaster(
auto backing = std::make_unique<BitmapSoftwareBacking>();
backing->frame_sink = frame_sink_;
backing->shared_bitmap_id = viz::SharedBitmap::GenerateId();
- base::MappedReadOnlyRegion mapped_region =
+ base::MappedReadOnlyRegion shm =
viz::bitmap_allocation::AllocateSharedBitmap(size, viz::RGBA_8888);
- backing->mapping = std::move(mapped_region.mapping);
- frame_sink_->DidAllocateSharedBitmap(
- viz::bitmap_allocation::ToMojoHandle(std::move(mapped_region.region)),
- backing->shared_bitmap_id);
+ backing->mapping = std::move(shm.mapping);
+ frame_sink_->DidAllocateSharedBitmap(std::move(shm.region),
+ backing->shared_bitmap_id);
resource.set_software_backing(std::move(backing));
}
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc
index 79c32f61b5d..e8533353bef 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.cc
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc
@@ -338,7 +338,7 @@ GpuRasterBufferProvider::GpuRasterBufferProvider(
const gfx::Size& max_tile_size,
bool unpremultiply_and_dither_low_bit_depth_tiles,
bool enable_oop_rasterization,
- int raster_metric_frequency)
+ float raster_metric_probability)
: compositor_context_provider_(compositor_context_provider),
worker_context_provider_(worker_context_provider),
use_gpu_memory_buffer_resources_(use_gpu_memory_buffer_resources),
@@ -348,9 +348,8 @@ GpuRasterBufferProvider::GpuRasterBufferProvider(
unpremultiply_and_dither_low_bit_depth_tiles_(
unpremultiply_and_dither_low_bit_depth_tiles),
enable_oop_rasterization_(enable_oop_rasterization),
- raster_metric_frequency_(raster_metric_frequency),
- random_generator_(base::RandUint64()),
- uniform_distribution_(1, raster_metric_frequency) {
+ random_generator_((uint32_t)base::RandUint64()),
+ bernoulli_distribution_(raster_metric_probability) {
DCHECK(compositor_context_provider);
DCHECK(worker_context_provider);
}
@@ -497,8 +496,7 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThreadInternal(
gpu::raster::RasterInterface* ri = scoped_context.RasterInterface();
DCHECK(ri);
- const bool measure_raster_metric =
- uniform_distribution_(random_generator_) == raster_metric_frequency_;
+ const bool measure_raster_metric = bernoulli_distribution_(random_generator_);
gfx::Rect playback_rect = raster_full_rect;
if (resource_has_previous_content) {
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.h b/chromium/cc/raster/gpu_raster_buffer_provider.h
index e6a435978a7..945b8b821a1 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.h
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.h
@@ -26,16 +26,17 @@ namespace cc {
class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
public:
- static constexpr int kRasterMetricFrequency = 100;
- GpuRasterBufferProvider(viz::ContextProvider* compositor_context_provider,
- viz::RasterContextProvider* worker_context_provider,
- bool use_gpu_memory_buffer_resources,
- int gpu_rasterization_msaa_sample_count,
- viz::ResourceFormat tile_format,
- const gfx::Size& max_tile_size,
- bool unpremultiply_and_dither_low_bit_depth_tiles,
- bool enable_oop_rasterization,
- int raster_metric_frequency = kRasterMetricFrequency);
+ static constexpr float kRasterMetricProbability = 0.01;
+ GpuRasterBufferProvider(
+ viz::ContextProvider* compositor_context_provider,
+ viz::RasterContextProvider* worker_context_provider,
+ bool use_gpu_memory_buffer_resources,
+ int gpu_rasterization_msaa_sample_count,
+ viz::ResourceFormat tile_format,
+ const gfx::Size& max_tile_size,
+ bool unpremultiply_and_dither_low_bit_depth_tiles,
+ bool enable_oop_rasterization,
+ float raster_metric_probability = kRasterMetricProbability);
GpuRasterBufferProvider(const GpuRasterBufferProvider&) = delete;
~GpuRasterBufferProvider() override;
@@ -154,7 +155,6 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
const gfx::Size max_tile_size_;
const bool unpremultiply_and_dither_low_bit_depth_tiles_;
const bool enable_oop_rasterization_;
- const int raster_metric_frequency_;
// Note that this lock should never be acquired while holding the raster
// context lock.
@@ -164,7 +164,7 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
// Accessed with the worker context lock acquired.
std::mt19937 random_generator_;
- std::uniform_int_distribution<int> uniform_distribution_;
+ std::bernoulli_distribution bernoulli_distribution_;
};
} // namespace cc
diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.cc b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
index daf5a89f012..6a40f4e513e 100644
--- a/chromium/cc/raster/one_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
@@ -320,7 +320,8 @@ void OneCopyRasterBufferProvider::PlaybackToStagingBuffer(
if (staging_buffer->gpu_memory_buffer) {
gfx::GpuMemoryBuffer* buffer = staging_buffer->gpu_memory_buffer.get();
- DCHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat()));
+ DCHECK_EQ(1u,
+ gfx::NumberOfPlanesForLinearBufferFormat(buffer->GetFormat()));
bool rv = buffer->Map();
DCHECK(rv);
DCHECK(buffer->memory(0));
diff --git a/chromium/cc/raster/paint_worklet_image_provider.cc b/chromium/cc/raster/paint_worklet_image_provider.cc
index 7312ba3dced..a3821403961 100644
--- a/chromium/cc/raster/paint_worklet_image_provider.cc
+++ b/chromium/cc/raster/paint_worklet_image_provider.cc
@@ -5,15 +5,13 @@
#include "cc/raster/paint_worklet_image_provider.h"
#include <utility>
-#include "cc/tiles/paint_worklet_image_cache.h"
+#include "base/bind_helpers.h"
namespace cc {
PaintWorkletImageProvider::PaintWorkletImageProvider(
- PaintWorkletImageCache* cache)
- : cache_(cache) {
- DCHECK(cache_);
-}
+ PaintWorkletRecordMap records)
+ : records_(std::move(records)) {}
PaintWorkletImageProvider::~PaintWorkletImageProvider() = default;
@@ -24,11 +22,12 @@ PaintWorkletImageProvider& PaintWorkletImageProvider::operator=(
PaintWorkletImageProvider&& other) = default;
ImageProvider::ScopedResult PaintWorkletImageProvider::GetPaintRecordResult(
- PaintWorkletInput* input) {
- std::pair<sk_sp<PaintRecord>, base::OnceCallback<void()>>
- record_and_callback = cache_->GetPaintRecordAndRef(input);
- return ImageProvider::ScopedResult(std::move(record_and_callback.first),
- std::move(record_and_callback.second));
+ scoped_refptr<PaintWorkletInput> input) {
+ // The |records_| contains all known PaintWorkletInputs, whether they are
+ // painted or not, so |input| should always exist in it.
+ auto it = records_.find(input);
+ DCHECK(it != records_.end());
+ return ImageProvider::ScopedResult(it->second);
}
} // namespace cc
diff --git a/chromium/cc/raster/paint_worklet_image_provider.h b/chromium/cc/raster/paint_worklet_image_provider.h
index 866a348efa3..6204c397e57 100644
--- a/chromium/cc/raster/paint_worklet_image_provider.h
+++ b/chromium/cc/raster/paint_worklet_image_provider.h
@@ -7,16 +7,20 @@
#include "cc/cc_export.h"
#include "cc/paint/image_provider.h"
+#include "cc/paint/paint_worklet_input.h"
namespace cc {
-class PaintWorkletImageCache;
-class PaintWorkletInput;
-// PaintWorkletImageProvider is a bridge between PaintWorkletImageCache and its
-// rasterization.
+// PaintWorkletImageProvider is a storage class for PaintWorklets and their
+// painted content for use during rasterisation.
+//
+// PaintWorklet-based images are not painted at Blink Paint time; instead a
+// placeholder PaintWorkletInput is put in place and the painting is done later
+// from the cc-impl thread. By the time raster happens the resultant PaintRecord
+// is available, and this class provides the lookup from input to record.
class CC_EXPORT PaintWorkletImageProvider {
public:
- explicit PaintWorkletImageProvider(PaintWorkletImageCache* cache);
+ explicit PaintWorkletImageProvider(PaintWorkletRecordMap records);
PaintWorkletImageProvider(const PaintWorkletImageProvider&) = delete;
PaintWorkletImageProvider(PaintWorkletImageProvider&& other);
~PaintWorkletImageProvider();
@@ -25,10 +29,11 @@ class CC_EXPORT PaintWorkletImageProvider {
delete;
PaintWorkletImageProvider& operator=(PaintWorkletImageProvider&& other);
- ImageProvider::ScopedResult GetPaintRecordResult(PaintWorkletInput* input);
+ ImageProvider::ScopedResult GetPaintRecordResult(
+ scoped_refptr<PaintWorkletInput> input);
private:
- PaintWorkletImageCache* cache_;
+ PaintWorkletRecordMap records_;
};
} // namespace cc
diff --git a/chromium/cc/raster/raster_buffer_provider.cc b/chromium/cc/raster/raster_buffer_provider.cc
index 6252168a3b1..c4fa5a9be41 100644
--- a/chromium/cc/raster/raster_buffer_provider.cc
+++ b/chromium/cc/raster/raster_buffer_provider.cc
@@ -46,6 +46,7 @@ bool IsSupportedPlaybackToMemoryFormat(viz::ResourceFormat format) {
case viz::YVU_420:
case viz::YUV_420_BIPLANAR:
case viz::UYVY_422:
+ case viz::P010:
return false;
}
NOTREACHED();
@@ -145,6 +146,7 @@ void RasterBufferProvider::PlaybackToMemory(
case viz::YVU_420:
case viz::YUV_420_BIPLANAR:
case viz::UYVY_422:
+ case viz::P010:
NOTREACHED();
return;
}
diff --git a/chromium/cc/raster/raster_source.cc b/chromium/cc/raster/raster_source.cc
index 8c490e481d0..95235b98fdc 100644
--- a/chromium/cc/raster/raster_source.cc
+++ b/chromium/cc/raster/raster_source.cc
@@ -245,6 +245,10 @@ gfx::Rect RasterSource::RecordedViewport() const {
return recorded_viewport_;
}
+bool RasterSource::HasText() const {
+ return display_list_ && display_list_->HasText();
+}
+
void RasterSource::AsValueInto(base::trace_event::TracedValue* array) const {
if (display_list_.get())
viz::TracedValue::AppendIDRef(display_list_.get(), array);
@@ -255,6 +259,13 @@ void RasterSource::DidBeginTracing() {
display_list_->EmitTraceSnapshot();
}
+std::vector<scoped_refptr<PaintWorkletInput>>
+RasterSource::GetPaintWorkletInputs() const {
+ if (!display_list_)
+ return {};
+ return display_list_->discardable_image_map().paint_worklet_inputs();
+}
+
RasterSource::PlaybackSettings::PlaybackSettings() = default;
RasterSource::PlaybackSettings::PlaybackSettings(const PlaybackSettings&) =
diff --git a/chromium/cc/raster/raster_source.h b/chromium/cc/raster/raster_source.h
index 4866e607fe7..e2af9afa527 100644
--- a/chromium/cc/raster/raster_source.h
+++ b/chromium/cc/raster/raster_source.h
@@ -103,6 +103,9 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
// Valid rectangle in which everything is recorded and can be rastered from.
virtual gfx::Rect RecordedViewport() const;
+ // Returns true if this raster source may try and draw text.
+ bool HasText() const;
+
// Tracing functionality.
virtual void DidBeginTracing();
virtual void AsValueInto(base::trace_event::TracedValue* array) const;
@@ -113,6 +116,8 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
return display_list_;
}
+ std::vector<scoped_refptr<PaintWorkletInput>> GetPaintWorkletInputs() const;
+
float recording_scale_factor() const { return recording_scale_factor_; }
SkColor background_color() const { return background_color_; }
diff --git a/chromium/cc/raster/raster_source_unittest.cc b/chromium/cc/raster/raster_source_unittest.cc
index 0bd9e4fc367..7c73489c4bb 100644
--- a/chromium/cc/raster/raster_source_unittest.cc
+++ b/chromium/cc/raster/raster_source_unittest.cc
@@ -182,63 +182,6 @@ TEST(RasterSourceTest, AnalyzeIsSolidScaled) {
}
}
-TEST(RasterSourceTest, MultiPaintWorkletImages) {
- gfx::Size layer_bounds(512, 512);
-
- std::unique_ptr<FakeRecordingSource> recording_source =
- FakeRecordingSource::CreateFilledRecordingSource(layer_bounds);
-
- scoped_refptr<TestPaintWorkletInput> input1 =
- base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(32.0f, 32.0f));
- scoped_refptr<TestPaintWorkletInput> input2 =
- base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(64.0f, 64.0f));
- scoped_refptr<TestPaintWorkletInput> input3 =
- base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(100.0f, 100.0f));
-
- PaintImage discardable_image[2][2];
- discardable_image[0][0] = CreatePaintWorkletPaintImage(input1);
- discardable_image[0][1] = CreatePaintWorkletPaintImage(input2);
- discardable_image[1][1] = CreatePaintWorkletPaintImage(input3);
-
- recording_source->add_draw_image(discardable_image[0][0], gfx::Point(0, 0));
- recording_source->add_draw_image(discardable_image[0][1], gfx::Point(260, 0));
- recording_source->add_draw_image(discardable_image[1][1],
- gfx::Point(260, 260));
- recording_source->Rerecord();
-
- scoped_refptr<RasterSource> raster = recording_source->CreateRasterSource();
-
- // Tile sized iterators. These should find only one image.
- {
- std::vector<const DrawImage*> images;
- raster->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), &images);
- EXPECT_EQ(1u, images.size());
- EXPECT_EQ(discardable_image[0][0], images[0]->paint_image());
- }
- // Shifted tile sized iterators. These should find only one image.
- {
- std::vector<const DrawImage*> images;
- raster->GetDiscardableImagesInRect(gfx::Rect(260, 260, 256, 256), &images);
- EXPECT_EQ(1u, images.size());
- EXPECT_EQ(discardable_image[1][1], images[0]->paint_image());
- }
- // Ensure there's no discardable pixel refs in the empty cell
- {
- std::vector<const DrawImage*> images;
- raster->GetDiscardableImagesInRect(gfx::Rect(0, 256, 256, 256), &images);
- EXPECT_EQ(0u, images.size());
- }
- // Layer sized iterators. These should find three images.
- {
- std::vector<const DrawImage*> images;
- raster->GetDiscardableImagesInRect(gfx::Rect(0, 0, 512, 512), &images);
- EXPECT_EQ(3u, images.size());
- EXPECT_EQ(discardable_image[0][0], images[0]->paint_image());
- EXPECT_EQ(discardable_image[0][1], images[1]->paint_image());
- EXPECT_EQ(discardable_image[1][1], images[2]->paint_image());
- }
-}
-
TEST(RasterSourceTest, PixelRefIteratorDiscardableRefsOneTile) {
gfx::Size layer_bounds(512, 512);
diff --git a/chromium/cc/raster/single_thread_task_graph_runner.cc b/chromium/cc/raster/single_thread_task_graph_runner.cc
index afb47e818a0..67e4ab32d81 100644
--- a/chromium/cc/raster/single_thread_task_graph_runner.cc
+++ b/chromium/cc/raster/single_thread_task_graph_runner.cc
@@ -9,7 +9,6 @@
#include <string>
#include "base/threading/simple_thread.h"
-#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
namespace cc {
@@ -83,8 +82,6 @@ void SingleThreadTaskGraphRunner::WaitForTasksToFinishRunning(
{
base::AutoLock lock(lock_);
- // http://crbug.com/902823
- base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
auto* task_namespace = work_queue_.GetNamespaceForToken(token);
diff --git a/chromium/cc/raster/staging_buffer_pool.cc b/chromium/cc/raster/staging_buffer_pool.cc
index 5970012097f..b601add276b 100644
--- a/chromium/cc/raster/staging_buffer_pool.cc
+++ b/chromium/cc/raster/staging_buffer_pool.cc
@@ -128,8 +128,7 @@ StagingBufferPool::StagingBufferPool(
free_staging_buffer_usage_in_bytes_(0),
staging_buffer_expiration_delay_(
base::TimeDelta::FromMilliseconds(kStagingBufferExpirationDelayMs)),
- reduce_memory_usage_pending_(false),
- weak_ptr_factory_(this) {
+ reduce_memory_usage_pending_(false) {
DCHECK(worker_context_provider_);
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "cc::StagingBufferPool", base::ThreadTaskRunnerHandle::Get());
diff --git a/chromium/cc/raster/staging_buffer_pool.h b/chromium/cc/raster/staging_buffer_pool.h
index 4b2953b01a5..bcea8ab2fa9 100644
--- a/chromium/cc/raster/staging_buffer_pool.h
+++ b/chromium/cc/raster/staging_buffer_pool.h
@@ -142,7 +142,7 @@ class CC_EXPORT StagingBufferPool
std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
- base::WeakPtrFactory<StagingBufferPool> weak_ptr_factory_;
+ base::WeakPtrFactory<StagingBufferPool> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/raster/synchronous_task_graph_runner.cc b/chromium/cc/raster/synchronous_task_graph_runner.cc
index 4ee102e943a..b7e0e94b672 100644
--- a/chromium/cc/raster/synchronous_task_graph_runner.cc
+++ b/chromium/cc/raster/synchronous_task_graph_runner.cc
@@ -10,7 +10,6 @@
#include <utility>
#include "base/threading/simple_thread.h"
-#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
namespace cc {
diff --git a/chromium/cc/raster/task_graph_work_queue.cc b/chromium/cc/raster/task_graph_work_queue.cc
index 2d04f52e6aa..c268f7eb00b 100644
--- a/chromium/cc/raster/task_graph_work_queue.cc
+++ b/chromium/cc/raster/task_graph_work_queue.cc
@@ -215,7 +215,7 @@ void TaskGraphWorkQueue::ScheduleTasks(NamespaceToken token, TaskGraph* graph) {
}))
continue;
- DCHECK(!base::ContainsValue(task_namespace.completed_tasks, node.task));
+ DCHECK(!base::Contains(task_namespace.completed_tasks, node.task));
node.task->state().DidCancel();
task_namespace.completed_tasks.push_back(node.task);
}
@@ -326,7 +326,7 @@ void TaskGraphWorkQueue::CompleteTask(PrioritizedTask completed_task) {
TaskNamespace::Vector& ready_to_run_namespaces =
ready_to_run_namespaces_[dependent_node.category];
- DCHECK(!base::ContainsValue(ready_to_run_namespaces, task_namespace));
+ DCHECK(!base::Contains(ready_to_run_namespaces, task_namespace));
ready_to_run_namespaces.push_back(task_namespace);
}
ready_to_run_namespaces_has_heap_properties = false;
diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
index bce36db08b2..ef6c2c73433 100644
--- a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
@@ -129,7 +129,7 @@ class ZeroCopyRasterBufferImpl : public RasterBuffer {
return;
}
- DCHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat(
+ DCHECK_EQ(1u, gfx::NumberOfPlanesForLinearBufferFormat(
gpu_memory_buffer_->GetFormat()));
bool rv = gpu_memory_buffer_->Map();
DCHECK(rv);
diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc
index 9c73860e220..e169cac0f0f 100644
--- a/chromium/cc/resources/resource_pool.cc
+++ b/chromium/cc/resources/resource_pool.cc
@@ -99,8 +99,7 @@ ResourcePool::ResourcePool(
disallow_non_exact_reuse_(disallow_non_exact_reuse),
tracing_id_(g_next_tracing_id.GetNext()),
flush_evicted_resources_deadline_(base::TimeTicks::Max()),
- clock_(base::DefaultTickClock::GetInstance()),
- weak_ptr_factory_(this) {
+ clock_(base::DefaultTickClock::GetInstance()) {
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "cc::ResourcePool", task_runner_.get());
memory_pressure_listener_.reset(
diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h
index b7f2f8d9e77..700bba9b88f 100644
--- a/chromium/cc/resources/resource_pool.h
+++ b/chromium/cc/resources/resource_pool.h
@@ -408,7 +408,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider {
const base::TickClock* clock_;
- base::WeakPtrFactory<ResourcePool> weak_ptr_factory_;
+ base::WeakPtrFactory<ResourcePool> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/scheduler/compositor_frame_reporter.cc b/chromium/cc/scheduler/compositor_frame_reporter.cc
index 9b4c7ac2a5f..1a41c5c6fec 100644
--- a/chromium/cc/scheduler/compositor_frame_reporter.cc
+++ b/chromium/cc/scheduler/compositor_frame_reporter.cc
@@ -4,36 +4,120 @@
#include "cc/scheduler/compositor_frame_reporter.h"
+#include <string>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/strcat.h"
#include "base/trace_event/trace_event.h"
+#include "cc/base/rolling_time_delta_history.h"
namespace cc {
+namespace {
+
+// When considering if a time is abnormal, compare the stage execution
+// time to this percentile from the previous times of the same stage.
+static constexpr double kAbnormalityPercentile = 95;
+
+// Use for determining abnormal execution times. If the sample size is less
+// than this then don't check for abnormal execution time.
+static constexpr size_t kMinimumTimeDeltaSampleSize = 20;
+
+static constexpr int kMissedFrameReportTypeCount =
+ static_cast<int>(CompositorFrameReporter::MissedFrameReportTypes::
+ kMissedFrameReportTypeCount);
+static constexpr int kStageTypeCount =
+ static_cast<int>(CompositorFrameReporter::StageType::kStageTypeCount);
-CompositorFrameReporter::CompositorFrameReporter() {
- TRACE_EVENT_ASYNC_BEGIN0("cc,benchmark", "PipelineReporter", this);
+// Names for CompositorFrameReporter::StageType, which should be updated in case
+// of changes to the enum.
+constexpr const char* kStageNames[]{
+ "BeginImplFrameToSendBeginMainFrame",
+ "SendBeginMainFrameToCommit",
+ "Commit",
+ "EndCommitToActivation",
+ "Activation",
+ "EndActivateToSubmitCompositorFrame",
+ "SubmitCompositorFrameToPresentationCompositorFrame",
+ "TotalLatency"};
+static_assert(sizeof(kStageNames) / sizeof(kStageNames[0]) == kStageTypeCount,
+ "Compositor latency stages has changed.");
+
+// Names for CompositorFrameReporter::MissedFrameReportTypes, which should be
+// updated in case of changes to the enum.
+constexpr const char* kReportTypeNames[]{"", "MissedFrame.",
+ "MissedFrameLatencyIncrease."};
+static_assert(sizeof(kReportTypeNames) / sizeof(kReportTypeNames[0]) ==
+ kMissedFrameReportTypeCount,
+ "Compositor latency report types has changed.");
+
+// This value should be recalculate in case of changes to the number of values
+// in CompositorFrameReporter::MissedFrameReportTypes or in
+// CompositorFrameReporter::StageType
+static constexpr int kMaxHistogramIndex =
+ 2 * kMissedFrameReportTypeCount * kStageTypeCount;
+static constexpr int kHistogramMin = 1;
+static constexpr int kHistogramMax = 350000;
+static constexpr int kHistogramBucketCount = 50;
+} // namespace
+
+CompositorFrameReporter::CompositorFrameReporter(bool is_single_threaded)
+ : is_single_threaded_(is_single_threaded) {
+ TRACE_EVENT_ASYNC_BEGIN1("cc,benchmark", "PipelineReporter", this,
+ "is_single_threaded", is_single_threaded);
}
CompositorFrameReporter::~CompositorFrameReporter() {
- TerminateFrame();
+ TerminateReporter();
}
-void CompositorFrameReporter::StartStage(const char* stage_name) {
- TRACE_EVENT_ASYNC_STEP_INTO0("cc,benchmark", "PipelineReporter", this,
- TRACE_STR_COPY(stage_name));
+void CompositorFrameReporter::StartStage(
+ CompositorFrameReporter::StageType stage_type,
+ base::TimeTicks start_time,
+ RollingTimeDeltaHistory* stage_time_delta_history) {
+ EndCurrentStage(start_time);
+ current_stage_.stage_type = stage_type;
+ current_stage_.start_time = start_time;
+ current_stage_.time_delta_history = stage_time_delta_history;
+ int stage_type_index = static_cast<int>(current_stage_.stage_type);
+ CHECK_LT(stage_type_index, static_cast<int>(StageType::kStageTypeCount));
+ CHECK_GE(stage_type_index, 0);
+ TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(
+ "cc,benchmark", "PipelineReporter", this,
+ TRACE_STR_COPY(kStageNames[stage_type_index]), start_time);
}
-void CompositorFrameReporter::SetFrameTerminationStatus(
- FrameTerminationStatus termination_status) {
+void CompositorFrameReporter::EndCurrentStage(base::TimeTicks end_time) {
+ if (current_stage_.start_time == base::TimeTicks())
+ return;
+ current_stage_.end_time = end_time;
+ stage_history_.emplace_back(current_stage_);
+ current_stage_.start_time = base::TimeTicks();
+ current_stage_.time_delta_history = nullptr;
+}
+
+void CompositorFrameReporter::MissedSubmittedFrame() {
+ submitted_frame_missed_deadline_ = true;
+}
+
+void CompositorFrameReporter::TerminateFrame(
+ FrameTerminationStatus termination_status,
+ base::TimeTicks termination_time) {
frame_termination_status_ = termination_status;
+ frame_termination_time_ = termination_time;
+ EndCurrentStage(frame_termination_time_);
}
-void CompositorFrameReporter::TerminateFrame() {
- const char* termination_status_str;
+void CompositorFrameReporter::TerminateReporter() {
+ DCHECK_EQ(current_stage_.start_time, base::TimeTicks());
+ bool report_latency = false;
+ const char* termination_status_str = nullptr;
switch (frame_termination_status_) {
- case FrameTerminationStatus::kSubmittedFrame:
- termination_status_str = "submitted_frame";
+ case FrameTerminationStatus::kPresentedFrame:
+ report_latency = true;
+ termination_status_str = "presented_frame";
break;
- case FrameTerminationStatus::kSubmittedFrameMissedDeadline:
- termination_status_str = "missed_frame";
+ case FrameTerminationStatus::kDidNotPresentFrame:
+ termination_status_str = "did_not_present_frame";
break;
case FrameTerminationStatus::kMainFrameAborted:
termination_status_str = "main_frame_aborted";
@@ -48,9 +132,96 @@ void CompositorFrameReporter::TerminateFrame() {
NOTREACHED();
break;
}
- TRACE_EVENT_ASYNC_END1("cc,benchmark", "PipelineReporter", this,
- "termination_status",
- TRACE_STR_COPY(termination_status_str));
- // TODO(alsan): UMA histogram reporting
+
+ const char* submission_status_str =
+ submitted_frame_missed_deadline_ ? "missed_frame" : "non_missed_frame";
+
+ TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP2(
+ "cc,benchmark", "PipelineReporter", this, frame_termination_time_,
+ "termination_status", TRACE_STR_COPY(termination_status_str),
+ "compositor_frame_submission_status",
+ TRACE_STR_COPY(submission_status_str));
+
+ // Only report histograms if the frame was presented.
+ if (report_latency) {
+ DCHECK(stage_history_.size());
+ stage_history_.emplace_back(
+ StageData{StageType::kTotalLatency, stage_history_.front().start_time,
+ stage_history_.back().end_time, nullptr});
+ ReportStageHistograms(submitted_frame_missed_deadline_);
+ }
+}
+
+void CompositorFrameReporter::ReportStageHistograms(bool missed_frame) const {
+ CompositorFrameReporter::MissedFrameReportTypes report_type =
+ missed_frame
+ ? CompositorFrameReporter::MissedFrameReportTypes::kMissedFrame
+ : CompositorFrameReporter::MissedFrameReportTypes::kNonMissedFrame;
+
+ for (const StageData& stage : stage_history_) {
+ base::TimeDelta stage_delta = stage.end_time - stage.start_time;
+ ReportHistogram(report_type, stage.stage_type, stage_delta);
+
+ if (!stage.time_delta_history)
+ continue;
+
+ if (!missed_frame) {
+ stage.time_delta_history->InsertSample(stage_delta);
+ } else {
+ // If enough sample data is recorded compare the stage duration with the
+ // known normal stage duration and if it's higher than normal, report the
+ // difference.
+ if (stage.time_delta_history->sample_count() >=
+ kMinimumTimeDeltaSampleSize) {
+ base::TimeDelta time_upper_limit = GetStateNormalUpperLimit(stage);
+ if (stage_delta > time_upper_limit) {
+ ReportHistogram(CompositorFrameReporter::MissedFrameReportTypes::
+ kMissedFrameLatencyIncrease,
+ stage.stage_type, stage_delta - time_upper_limit);
+ }
+ }
+
+ // In case of a missing frame, remove a sample from the recorded normal
+ // stages. This invalidates the recorded normal durations if at a point
+ // all frames start missing for a while.
+ stage.time_delta_history->RemoveOldestSample();
+ }
+ }
+}
+
+void CompositorFrameReporter::ReportHistogram(
+ CompositorFrameReporter::MissedFrameReportTypes report_type,
+ CompositorFrameReporter::StageType stage_type,
+ base::TimeDelta time_delta) const {
+ const int report_type_index = static_cast<int>(report_type);
+ const int stage_type_index = static_cast<int>(stage_type);
+ const int histogram_index =
+ (stage_type_index * kMissedFrameReportTypeCount + report_type_index) * 2 +
+ (is_single_threaded_ ? 1 : 0);
+
+ CHECK_LT(stage_type_index, kStageTypeCount);
+ CHECK_GE(stage_type_index, 0);
+ CHECK_LT(report_type_index, kMissedFrameReportTypeCount);
+ CHECK_GE(report_type_index, 0);
+ CHECK_LT(histogram_index, kMaxHistogramIndex);
+ CHECK_GE(histogram_index, 0);
+
+ const char* compositor_type = is_single_threaded_ ? "SingleThreaded" : "";
+ const std::string name =
+ base::StrCat({compositor_type, "CompositorLatency.",
+ kReportTypeNames[static_cast<int>(report_type)],
+ kStageNames[static_cast<int>(stage_type)]});
+
+ STATIC_HISTOGRAM_POINTER_GROUP(
+ name, histogram_index, kMaxHistogramIndex,
+ AddTimeMicrosecondsGranularity(time_delta),
+ base::Histogram::FactoryGet(
+ name, kHistogramMin, kHistogramMax, kHistogramBucketCount,
+ base::HistogramBase::kUmaTargetedHistogramFlag));
+}
+
+base::TimeDelta CompositorFrameReporter::GetStateNormalUpperLimit(
+ const StageData& stage) const {
+ return stage.time_delta_history->Percentile(kAbnormalityPercentile);
}
} // namespace cc
diff --git a/chromium/cc/scheduler/compositor_frame_reporter.h b/chromium/cc/scheduler/compositor_frame_reporter.h
index b122693b1d2..ae7d8bba562 100644
--- a/chromium/cc/scheduler/compositor_frame_reporter.h
+++ b/chromium/cc/scheduler/compositor_frame_reporter.h
@@ -5,30 +5,36 @@
#ifndef CC_SCHEDULER_COMPOSITOR_FRAME_REPORTER_H_
#define CC_SCHEDULER_COMPOSITOR_FRAME_REPORTER_H_
+#include <vector>
+
+#include "base/time/time.h"
#include "cc/base/base_export.h"
#include "cc/cc_export.h"
namespace cc {
-// This is used for tracing the pipeline stages of a single frame.
+class RollingTimeDeltaHistory;
+
+// This is used for tracing and reporting the duration of pipeline stages within
+// a single frame.
//
// For each stage in the frame pipeline, calling StartStage will start tracing
// that stage (and end any currently running stages).
-// TODO(alsan): Report stage durations to UMA.
+//
+// If the tracked frame is submitted (i.e. the frame termination status is
+// kSubmittedFrame or kSubmittedFrameMissedDeadline), then the duration of each
+// stage along with the total latency will be reported to UMA. These reported
+// durations will be differentiated by whether the compositor is single threaded
+// and whether the submitted frame missed the deadline. The format of each stage
+// reported to UMA is "[SingleThreaded]Compositor.[MissedFrame.].<StageName>".
class CC_EXPORT CompositorFrameReporter {
public:
- enum FrameTerminationStatus {
- // Compositor frame (with main thread updates) is submitted before a new
- // BeginImplFrame is issued (i.e. BF -> BMF -> Commit -> Activate ->
- // Submit).
- kSubmittedFrame,
-
- // Same as SubmittedFrame, but with the condition that there is another
- // frame being processed in the pipeline at an earlier stage.
- // This would imply that a new BeginImplFrame was issued during the lifetime
- // of this reporter, and therefore it missed its deadline
- // (e.g. BF1 -> BMF1 -> Submit -> BF2 -> Commit1 -> Activate1 -> BMF2 ->
- // Submit).
- kSubmittedFrameMissedDeadline,
+ enum class FrameTerminationStatus {
+ // The tracked compositor frame was presented.
+ kPresentedFrame,
+
+ // The tracked compositor frame was submitted to the display compositor but
+ // was not presented.
+ kDidNotPresentFrame,
// Main frame was aborted; the reporter will not continue reporting.
kMainFrameAborted,
@@ -47,20 +53,76 @@ class CC_EXPORT CompositorFrameReporter {
kUnknown
};
- CompositorFrameReporter();
- CompositorFrameReporter(const CompositorFrameReporter& reporter) = delete;
+ enum class MissedFrameReportTypes {
+ kNonMissedFrame,
+ kMissedFrame,
+ kMissedFrameLatencyIncrease,
+ kMissedFrameReportTypeCount
+ };
+
+ enum class StageType {
+ kBeginImplFrameToSendBeginMainFrame,
+ kSendBeginMainFrameToCommit,
+ kCommit,
+ kEndCommitToActivation,
+ kActivation,
+ kEndActivateToSubmitCompositorFrame,
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ kTotalLatency,
+ kStageTypeCount
+ };
+
+ explicit CompositorFrameReporter(bool is_single_threaded = false);
~CompositorFrameReporter();
+ CompositorFrameReporter(const CompositorFrameReporter& reporter) = delete;
CompositorFrameReporter& operator=(const CompositorFrameReporter& reporter) =
delete;
- void StartStage(const char* stage_name);
- void SetFrameTerminationStatus(FrameTerminationStatus termination_status);
+ void MissedSubmittedFrame();
+
+ // Note that the started stage may be reported to UMA. If the histogram is
+ // intended to be reported then the histograms.xml file must be updated too.
+ void StartStage(StageType stage_type,
+ base::TimeTicks start_time,
+ RollingTimeDeltaHistory* stage_time_delta_history);
+ void TerminateFrame(FrameTerminationStatus termination_status,
+ base::TimeTicks termination_time);
+
+ int StageHistorySizeForTesting() { return stage_history_.size(); }
+
+ protected:
+ struct StageData {
+ StageType stage_type;
+ base::TimeTicks start_time;
+ base::TimeTicks end_time;
+ RollingTimeDeltaHistory* time_delta_history;
+ };
+
+ StageData current_stage_;
+
+ // Stage data is recorded here. On destruction these stages will be reported
+ // to UMA if the termination status is |kPresentedFrame|. Reported data will
+ // be divided based on the frame submission status.
+ std::vector<StageData> stage_history_;
private:
+ void TerminateReporter();
+ void EndCurrentStage(base::TimeTicks end_time);
+ void ReportStageHistograms(bool missed_frame) const;
+ void ReportHistogram(
+ CompositorFrameReporter::MissedFrameReportTypes report_type,
+ StageType stage_type,
+ base::TimeDelta time_delta) const;
+ // Returns true if the stage duration is greater than |kAbnormalityPercentile|
+ // of its RollingTimeDeltaHistory.
+ base::TimeDelta GetStateNormalUpperLimit(const StageData& stage) const;
+
+ const bool is_single_threaded_;
+ bool submitted_frame_missed_deadline_ = false;
+ base::TimeTicks frame_termination_time_;
FrameTerminationStatus frame_termination_status_ =
FrameTerminationStatus::kUnknown;
- void TerminateFrame();
};
} // namespace cc
diff --git a/chromium/cc/scheduler/compositor_frame_reporter_unittest.cc b/chromium/cc/scheduler/compositor_frame_reporter_unittest.cc
new file mode 100644
index 00000000000..d23a51bebc0
--- /dev/null
+++ b/chromium/cc/scheduler/compositor_frame_reporter_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2019 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/scheduler/compositor_frame_reporter.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "cc/scheduler/compositor_frame_reporting_controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class CompositorFrameReporterTest;
+
+class CompositorFrameReporterTest : public testing::Test {
+ public:
+ CompositorFrameReporterTest()
+ : pipeline_reporter_(std::make_unique<CompositorFrameReporter>()) {
+ AdvanceNowByMs(1);
+ }
+
+ void AdvanceNowByMs(int advance_ms) {
+ now_ += base::TimeDelta::FromMicroseconds(advance_ms);
+ }
+
+ base::TimeTicks Now() { return now_; }
+
+ protected:
+ std::unique_ptr<CompositorFrameReporter> pipeline_reporter_;
+ base::TimeTicks now_;
+};
+
+TEST_F(CompositorFrameReporterTest, MainFrameAbortedReportingTest) {
+ base::HistogramTester histogram_tester;
+
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now(), nullptr);
+ EXPECT_EQ(0, pipeline_reporter_->StageHistorySizeForTesting());
+
+ AdvanceNowByMs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now(),
+ nullptr);
+ EXPECT_EQ(1, pipeline_reporter_->StageHistorySizeForTesting());
+
+ AdvanceNowByMs(2);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kMainFrameAborted,
+ Now());
+ EXPECT_EQ(2, pipeline_reporter_->StageHistorySizeForTesting());
+
+ pipeline_reporter_ = nullptr;
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.BeginImplFrameToSendBeginMainFrame", 0);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.SendBeginMainFrameToCommit", 0);
+}
+
+TEST_F(CompositorFrameReporterTest, ReplacedByNewReporterReportingTest) {
+ base::HistogramTester histogram_tester;
+
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now(), nullptr);
+ EXPECT_EQ(0, pipeline_reporter_->StageHistorySizeForTesting());
+
+ AdvanceNowByMs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now(),
+ nullptr);
+ EXPECT_EQ(1, pipeline_reporter_->StageHistorySizeForTesting());
+
+ AdvanceNowByMs(2);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kReplacedByNewReporter,
+ Now());
+ EXPECT_EQ(2, pipeline_reporter_->StageHistorySizeForTesting());
+
+ pipeline_reporter_ = nullptr;
+ histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 0);
+ histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation",
+ 0);
+}
+
+TEST_F(CompositorFrameReporterTest, SubmittedFrameReportingTest) {
+ base::HistogramTester histogram_tester;
+
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kActivation, Now(), nullptr);
+ EXPECT_EQ(0, pipeline_reporter_->StageHistorySizeForTesting());
+
+ AdvanceNowByMs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now(), nullptr);
+ EXPECT_EQ(1, pipeline_reporter_->StageHistorySizeForTesting());
+
+ AdvanceNowByMs(2);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+ EXPECT_EQ(2, pipeline_reporter_->StageHistorySizeForTesting());
+
+ pipeline_reporter_ = nullptr;
+ histogram_tester.ExpectTotalCount("CompositorLatency.Activation", 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.EndActivateToSubmitCompositorFrame", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.TotalLatency", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Activation",
+ 0);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.EndActivateToSubmitCompositorFrame", 0);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.TotalLatency", 0);
+
+ histogram_tester.ExpectBucketCount("CompositorLatency.Activation", 3, 1);
+ histogram_tester.ExpectBucketCount(
+ "CompositorLatency.EndActivateToSubmitCompositorFrame", 2, 1);
+ histogram_tester.ExpectBucketCount("CompositorLatency.TotalLatency", 5, 1);
+}
+
+TEST_F(CompositorFrameReporterTest, SubmittedMissedFrameReportingTest) {
+ base::HistogramTester histogram_tester;
+
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now(),
+ nullptr);
+ EXPECT_EQ(0, pipeline_reporter_->StageHistorySizeForTesting());
+
+ AdvanceNowByMs(3);
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now(), nullptr);
+ EXPECT_EQ(1, pipeline_reporter_->StageHistorySizeForTesting());
+
+ AdvanceNowByMs(2);
+ pipeline_reporter_->MissedSubmittedFrame();
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+ EXPECT_EQ(2, pipeline_reporter_->StageHistorySizeForTesting());
+
+ pipeline_reporter_ = nullptr;
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.SendBeginMainFrameToCommit", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Commit", 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.TotalLatency", 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.SendBeginMainFrameToCommit", 0);
+ histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 0);
+ histogram_tester.ExpectTotalCount("CompositorLatency.TotalLatency", 0);
+
+ histogram_tester.ExpectBucketCount(
+ "CompositorLatency.MissedFrame.SendBeginMainFrameToCommit", 3, 1);
+ histogram_tester.ExpectBucketCount("CompositorLatency.MissedFrame.Commit", 2,
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "CompositorLatency.MissedFrame.TotalLatency", 5, 1);
+}
+
+TEST_F(CompositorFrameReporterTest, MissedFrameLatencyIncreaseReportingTest) {
+ base::HistogramTester histogram_tester;
+ RollingTimeDeltaHistory time_delta_history(50);
+ RollingTimeDeltaHistory time_delta_history2(50);
+
+ // Terminate this frame since it will get destroyed in the for loop.
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame,
+ Now());
+
+ // Submit 19 non-missed frames.
+ for (int i = 0; i < 19; ++i) {
+ pipeline_reporter_ = std::make_unique<CompositorFrameReporter>();
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now(), &time_delta_history);
+ AdvanceNowByMs(1);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now(),
+ &time_delta_history2);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame,
+ Now());
+ }
+ pipeline_reporter_ = nullptr;
+ EXPECT_EQ((size_t)19, time_delta_history.sample_count());
+ EXPECT_EQ((size_t)19, time_delta_history2.sample_count());
+ histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 19);
+ histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation",
+ 19);
+
+ // Submit 3 frames missed frames. This will remove 3 sample from the front of
+ // time delta history. And 16 sample will be in the time delta history.
+ for (int i = 0; i < 3; ++i) {
+ pipeline_reporter_ = std::make_unique<CompositorFrameReporter>();
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now(), &time_delta_history);
+ AdvanceNowByMs(100);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now(),
+ &time_delta_history2);
+ pipeline_reporter_->MissedSubmittedFrame();
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame,
+ Now());
+ }
+ pipeline_reporter_ = nullptr;
+ EXPECT_EQ((size_t)16, time_delta_history.sample_count());
+ EXPECT_EQ((size_t)16, time_delta_history2.sample_count());
+ DCHECK_EQ(time_delta_history.sample_count(), (size_t)16);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrameLatencyIncrease.Commit", 0);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrameLatencyIncrease.EndCommitToActivation", 0);
+ histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Commit", 3);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.EndCommitToActivation", 3);
+
+ // Submit 5 frame so that missed frame duration increases would be reported.
+ for (int i = 0; i < 5; ++i) {
+ pipeline_reporter_ = std::make_unique<CompositorFrameReporter>();
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now(), &time_delta_history);
+ AdvanceNowByMs(1);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now(),
+ &time_delta_history2);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame,
+ Now());
+ }
+ pipeline_reporter_ = nullptr;
+ EXPECT_EQ((size_t)21, time_delta_history.sample_count());
+ EXPECT_EQ((size_t)21, time_delta_history2.sample_count());
+
+ histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 24);
+ histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation",
+ 24);
+
+ // Submit missed frame that is not abnormal (more than 95 percentile of the
+ // frame history). This brings down the time delta history count to 20.
+ pipeline_reporter_ = std::make_unique<CompositorFrameReporter>();
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now(), &time_delta_history);
+ AdvanceNowByMs(1);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now(),
+ &time_delta_history2);
+ pipeline_reporter_->MissedSubmittedFrame();
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+ pipeline_reporter_ = nullptr;
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrameLatencyIncrease.Commit", 0);
+ histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Commit", 4);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.EndCommitToActivation", 4);
+
+ EXPECT_EQ((size_t)20, time_delta_history.sample_count());
+ EXPECT_EQ((size_t)20, time_delta_history2.sample_count());
+
+ // Submit missed frame that is abnormal (more than 95 percentile of the
+ // frame history).
+ pipeline_reporter_ = std::make_unique<CompositorFrameReporter>();
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now(), &time_delta_history);
+ AdvanceNowByMs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now(),
+ &time_delta_history2);
+ pipeline_reporter_->MissedSubmittedFrame();
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+ pipeline_reporter_ = nullptr;
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrameLatencyIncrease.Commit", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Commit", 5);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.EndCommitToActivation", 5);
+
+ // Submit not-missed frame with abnormal times.
+ pipeline_reporter_ = std::make_unique<CompositorFrameReporter>();
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now(), &time_delta_history);
+ AdvanceNowByMs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now(),
+ &time_delta_history2);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+ pipeline_reporter_ = nullptr;
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrameLatencyIncrease.Commit", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 25);
+ histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation",
+ 25);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/scheduler/compositor_frame_reporting_controller.cc b/chromium/cc/scheduler/compositor_frame_reporting_controller.cc
index 1b17021fd22..dd74268707a 100644
--- a/chromium/cc/scheduler/compositor_frame_reporting_controller.cc
+++ b/chromium/cc/scheduler/compositor_frame_reporting_controller.cc
@@ -5,36 +5,91 @@
#include "cc/scheduler/compositor_frame_reporting_controller.h"
#include "cc/scheduler/compositor_frame_reporter.h"
+#include "components/viz/common/quads/compositor_frame_metadata.h"
namespace cc {
-CompositorFrameReportingController::CompositorFrameReportingController() {}
+namespace {
+using StageType = CompositorFrameReporter::StageType;
+RollingTimeDeltaHistory* GetStageHistory(
+ std::unique_ptr<RollingTimeDeltaHistory> stage_history_[],
+ StageType stage_type) {
+ return stage_history_[static_cast<int>(stage_type)].get();
+}
+
+static constexpr size_t kMaxHistorySize = 50;
+} // namespace
+
+CompositorFrameReportingController::CompositorFrameReportingController(
+ bool is_single_threaded)
+ : is_single_threaded_(is_single_threaded) {
+ for (int i = 0; i < static_cast<int>(
+ CompositorFrameReporter::StageType::kStageTypeCount);
+ ++i) {
+ stage_history_[i] =
+ std::make_unique<RollingTimeDeltaHistory>(kMaxHistorySize);
+ }
+}
CompositorFrameReportingController::~CompositorFrameReportingController() {
+ base::TimeTicks now = Now();
for (int i = 0; i < PipelineStage::kNumPipelineStages; ++i) {
if (reporters_[i]) {
- reporters_[i]->SetFrameTerminationStatus(
- CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame);
+ reporters_[i]->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame,
+ now);
}
}
+ for (auto& pair : submitted_compositor_frames_) {
+ pair.reporter->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kDidNotPresentFrame,
+ Now());
+ }
+}
+
+CompositorFrameReportingController::SubmittedCompositorFrame::
+ SubmittedCompositorFrame() = default;
+CompositorFrameReportingController::SubmittedCompositorFrame::
+ SubmittedCompositorFrame(uint32_t frame_token,
+ std::unique_ptr<CompositorFrameReporter> reporter)
+ : frame_token(frame_token), reporter(std::move(reporter)) {}
+CompositorFrameReportingController::SubmittedCompositorFrame::
+ ~SubmittedCompositorFrame() = default;
+
+CompositorFrameReportingController::SubmittedCompositorFrame::
+ SubmittedCompositorFrame(SubmittedCompositorFrame&& other) = default;
+
+base::TimeTicks CompositorFrameReportingController::Now() const {
+ return base::TimeTicks::Now();
}
void CompositorFrameReportingController::WillBeginImplFrame() {
+ base::TimeTicks begin_time = Now();
+ if (reporters_[PipelineStage::kBeginImplFrame]) {
+ reporters_[PipelineStage::kBeginImplFrame]->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kReplacedByNewReporter,
+ begin_time);
+ }
std::unique_ptr<CompositorFrameReporter> reporter =
- std::make_unique<CompositorFrameReporter>();
- reporter->StartStage("BeginImplFrameToSendBeginMainFrame");
- if (reporters_[PipelineStage::kBeginImplFrame])
- reporters_[PipelineStage::kBeginImplFrame]->SetFrameTerminationStatus(
- CompositorFrameReporter::FrameTerminationStatus::
- kReplacedByNewReporter);
+ std::make_unique<CompositorFrameReporter>(is_single_threaded_);
+ reporter->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ begin_time,
+ GetStageHistory(stage_history_, CompositorFrameReporter::StageType::
+ kBeginImplFrameToSendBeginMainFrame));
reporters_[PipelineStage::kBeginImplFrame] = std::move(reporter);
}
void CompositorFrameReportingController::WillBeginMainFrame() {
DCHECK(reporters_[PipelineStage::kBeginImplFrame]);
- DCHECK(reporters_[PipelineStage::kBeginMainFrame] !=
- reporters_[PipelineStage::kBeginImplFrame]);
+ // We need to use .get() below because operator<< in std::unique_ptr is a
+ // C++20 feature.
+ DCHECK_NE(reporters_[PipelineStage::kBeginMainFrame].get(),
+ reporters_[PipelineStage::kBeginImplFrame].get());
reporters_[PipelineStage::kBeginImplFrame]->StartStage(
- "SendBeginMainFrameToCommit");
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now(),
+ GetStageHistory(
+ stage_history_,
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit));
AdvanceReporterStage(PipelineStage::kBeginImplFrame,
PipelineStage::kBeginMainFrame);
}
@@ -43,20 +98,26 @@ void CompositorFrameReportingController::BeginMainFrameAborted() {
DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
std::unique_ptr<CompositorFrameReporter> aborted_frame_reporter =
std::move(reporters_[PipelineStage::kBeginMainFrame]);
- aborted_frame_reporter->StartStage("BeginMainFrameAborted");
- aborted_frame_reporter->SetFrameTerminationStatus(
- CompositorFrameReporter::FrameTerminationStatus::kMainFrameAborted);
+ aborted_frame_reporter->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kMainFrameAborted,
+ Now());
}
void CompositorFrameReportingController::WillCommit() {
DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
- reporters_[PipelineStage::kBeginMainFrame]->StartStage("Commit");
+ reporters_[PipelineStage::kBeginMainFrame]->StartStage(
+ CompositorFrameReporter::StageType::kCommit, Now(),
+ GetStageHistory(stage_history_,
+ CompositorFrameReporter::StageType::kCommit));
}
void CompositorFrameReportingController::DidCommit() {
DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
reporters_[PipelineStage::kBeginMainFrame]->StartStage(
- "EndCommitToActivation");
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now(),
+ GetStageHistory(
+ stage_history_,
+ CompositorFrameReporter::StageType::kEndCommitToActivation));
AdvanceReporterStage(PipelineStage::kBeginMainFrame, PipelineStage::kCommit);
}
@@ -65,11 +126,15 @@ void CompositorFrameReportingController::WillInvalidateOnImplSide() {
// TODO(alsan): Report latency of impl side invalidations.
next_activate_has_invalidation_ = true;
}
+
void CompositorFrameReportingController::WillActivate() {
DCHECK(reporters_[PipelineStage::kCommit] || next_activate_has_invalidation_);
if (!reporters_[PipelineStage::kCommit])
return;
- reporters_[PipelineStage::kCommit]->StartStage("Activation");
+ reporters_[PipelineStage::kCommit]->StartStage(
+ CompositorFrameReporter::StageType::kActivation, Now(),
+ GetStageHistory(stage_history_,
+ CompositorFrameReporter::StageType::kActivation));
}
void CompositorFrameReportingController::DidActivate() {
@@ -78,45 +143,74 @@ void CompositorFrameReportingController::DidActivate() {
if (!reporters_[PipelineStage::kCommit])
return;
reporters_[PipelineStage::kCommit]->StartStage(
- "EndActivateToSubmitCompositorFrame");
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now(),
+ GetStageHistory(stage_history_, CompositorFrameReporter::StageType::
+ kEndActivateToSubmitCompositorFrame));
AdvanceReporterStage(PipelineStage::kCommit, PipelineStage::kActivate);
}
-void CompositorFrameReportingController::DidSubmitCompositorFrame() {
+void CompositorFrameReportingController::DidSubmitCompositorFrame(
+ uint32_t frame_token) {
if (!reporters_[PipelineStage::kActivate])
return;
std::unique_ptr<CompositorFrameReporter> submitted_reporter =
std::move(reporters_[PipelineStage::kActivate]);
- submitted_reporter->StartStage("SubmitCompositorFrame");
// If there are any other reporters active on the other stages of the
// pipeline then that means a new frame was started during the duration of
// this reporter and therefore the frame being tracked missed the deadline.
if (reporters_[PipelineStage::kBeginImplFrame] ||
reporters_[PipelineStage::kBeginMainFrame] ||
reporters_[PipelineStage::kCommit]) {
- submitted_reporter->SetFrameTerminationStatus(
- CompositorFrameReporter::FrameTerminationStatus::
- kSubmittedFrameMissedDeadline);
- } else {
- submitted_reporter->SetFrameTerminationStatus(
- CompositorFrameReporter::FrameTerminationStatus::kSubmittedFrame);
+ submitted_reporter->MissedSubmittedFrame();
}
+ submitted_reporter->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now(),
+ GetStageHistory(stage_history_,
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame));
+ submitted_compositor_frames_.emplace_back(frame_token,
+ std::move(submitted_reporter));
}
void CompositorFrameReportingController::DidNotProduceFrame() {
- if (reporters_[PipelineStage::kActivate])
- reporters_[PipelineStage::kActivate]->SetFrameTerminationStatus(
- CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame);
+ if (!reporters_[PipelineStage::kActivate])
+ return;
+ reporters_[PipelineStage::kActivate]->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame,
+ Now());
reporters_[PipelineStage::kActivate] = nullptr;
}
+void CompositorFrameReportingController::DidPresentCompositorFrame(
+ uint32_t frame_token,
+ base::TimeTicks presentation_time) {
+ while (!submitted_compositor_frames_.empty()) {
+ auto submitted_frame = submitted_compositor_frames_.begin();
+ if (viz::FrameTokenGT(submitted_frame->frame_token, frame_token))
+ break;
+
+ auto termination_status =
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame;
+ if (submitted_frame->frame_token != frame_token)
+ termination_status =
+ CompositorFrameReporter::FrameTerminationStatus::kDidNotPresentFrame;
+
+ submitted_frame->reporter->TerminateFrame(termination_status,
+ presentation_time);
+ submitted_compositor_frames_.erase(submitted_frame);
+ }
+}
+
void CompositorFrameReportingController::AdvanceReporterStage(
PipelineStage start,
PipelineStage target) {
if (reporters_[target]) {
- reporters_[target]->SetFrameTerminationStatus(
- CompositorFrameReporter::FrameTerminationStatus::
- kReplacedByNewReporter);
+ reporters_[target]->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kReplacedByNewReporter,
+ Now());
}
reporters_[target] = std::move(reporters_[start]);
}
diff --git a/chromium/cc/scheduler/compositor_frame_reporting_controller.h b/chromium/cc/scheduler/compositor_frame_reporting_controller.h
index 9b72cffc28d..a481593c592 100644
--- a/chromium/cc/scheduler/compositor_frame_reporting_controller.h
+++ b/chromium/cc/scheduler/compositor_frame_reporting_controller.h
@@ -6,13 +6,16 @@
#define CC_SCHEDULER_COMPOSITOR_FRAME_REPORTING_CONTROLLER_H_
#include <memory>
+#include <vector>
#include "base/time/time.h"
#include "cc/base/base_export.h"
+#include "cc/base/rolling_time_delta_history.h"
#include "cc/cc_export.h"
+#include "cc/scheduler/compositor_frame_reporter.h"
namespace cc {
-class CompositorFrameReporter;
+class RollingTimeDeltaHistory;
// This is used for managing simultaneous CompositorFrameReporter instances
// in the case that the compositor has high latency. Calling one of the
@@ -31,7 +34,7 @@ class CC_EXPORT CompositorFrameReportingController {
kNumPipelineStages
};
- CompositorFrameReportingController();
+ explicit CompositorFrameReportingController(bool is_single_threaded = false);
virtual ~CompositorFrameReportingController();
CompositorFrameReportingController(
@@ -48,17 +51,42 @@ class CC_EXPORT CompositorFrameReportingController {
virtual void DidCommit();
virtual void WillActivate();
virtual void DidActivate();
- virtual void DidSubmitCompositorFrame();
+ virtual void DidSubmitCompositorFrame(uint32_t frame_token);
virtual void DidNotProduceFrame();
+ virtual void DidPresentCompositorFrame(uint32_t frame_token,
+ base::TimeTicks presentation_time);
protected:
+ struct SubmittedCompositorFrame {
+ uint32_t frame_token;
+ std::unique_ptr<CompositorFrameReporter> reporter;
+ SubmittedCompositorFrame();
+ SubmittedCompositorFrame(uint32_t frame_token,
+ std::unique_ptr<CompositorFrameReporter> reporter);
+ SubmittedCompositorFrame(SubmittedCompositorFrame&& other);
+ ~SubmittedCompositorFrame();
+ };
+ base::TimeTicks Now() const;
std::unique_ptr<CompositorFrameReporter>
reporters_[PipelineStage::kNumPipelineStages];
private:
void AdvanceReporterStage(PipelineStage start, PipelineStage target);
+ // Used by the managed reporters to differentiate the histogram names when
+ // reporting to UMA.
+ const bool is_single_threaded_;
bool next_activate_has_invalidation_ = false;
+
+ // Mapping of frame token to pipeline reporter for submitted compositor
+ // frames.
+ base::circular_deque<SubmittedCompositorFrame> submitted_compositor_frames_;
+
+ // These keep track of stage durations for when a frame did not miss a
+ // deadline. The history is used by reporter instances to determine if a
+ // missed frame had a stage duration that was abnormally large.
+ std::unique_ptr<RollingTimeDeltaHistory> stage_history_[static_cast<size_t>(
+ CompositorFrameReporter::StageType::kStageTypeCount)];
};
} // namespace cc
diff --git a/chromium/cc/scheduler/compositor_frame_reporting_controller_unittest.cc b/chromium/cc/scheduler/compositor_frame_reporting_controller_unittest.cc
index 94f6ffdfa66..8210d247bcc 100644
--- a/chromium/cc/scheduler/compositor_frame_reporting_controller_unittest.cc
+++ b/chromium/cc/scheduler/compositor_frame_reporting_controller_unittest.cc
@@ -5,6 +5,8 @@
#include "cc/scheduler/compositor_frame_reporting_controller.h"
#include "base/macros.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
@@ -79,17 +81,27 @@ class CompositorFrameReportingControllerTest : public testing::Test {
reporting_controller_.DidActivate();
}
- void SimulateSubmitCompositorFrame() {
+ void SimulateSubmitCompositorFrame(uint32_t frame_token) {
if (!reporting_controller_.reporters()
[CompositorFrameReportingController::PipelineStage::kActivate])
SimulateActivate();
CHECK(reporting_controller_.reporters()
[CompositorFrameReportingController::PipelineStage::kActivate]);
- reporting_controller_.DidSubmitCompositorFrame();
+ reporting_controller_.DidSubmitCompositorFrame(frame_token);
+ }
+
+ void SimulatePresentCompositorFrame() {
+ ++next_token_;
+ SimulateSubmitCompositorFrame(*next_token_);
+ reporting_controller_.DidPresentCompositorFrame(*next_token_,
+ base::TimeTicks::Now());
}
protected:
TestCompositorFrameReportingController reporting_controller_;
+
+ private:
+ viz::FrameTokenGenerator next_token_;
};
TEST_F(CompositorFrameReportingControllerTest, ActiveReporterCounts) {
@@ -108,24 +120,24 @@ TEST_F(CompositorFrameReportingControllerTest, ActiveReporterCounts) {
EXPECT_EQ(1, reporting_controller_.ActiveReporters());
// BF -> BF
- // Should replace previous reporter
+ // Should replace previous reporter.
reporting_controller_.WillBeginImplFrame();
EXPECT_EQ(1, reporting_controller_.ActiveReporters());
// BF -> BMF -> BF
- // Should add new reporter
+ // Should add new reporter.
reporting_controller_.WillBeginMainFrame();
reporting_controller_.WillBeginImplFrame();
EXPECT_EQ(2, reporting_controller_.ActiveReporters());
// BF -> BMF -> BF -> Commit
- // Should stay same
+ // Should stay same.
reporting_controller_.WillCommit();
reporting_controller_.DidCommit();
EXPECT_EQ(2, reporting_controller_.ActiveReporters());
// BF -> BMF -> BF -> Commit -> BMF -> Activate -> Commit -> Activation
- // Having two reporters at Activate phase should delete the older one
+ // Having two reporters at Activate phase should delete the older one.
reporting_controller_.WillBeginMainFrame();
reporting_controller_.WillActivate();
reporting_controller_.DidActivate();
@@ -135,10 +147,10 @@ TEST_F(CompositorFrameReportingControllerTest, ActiveReporterCounts) {
reporting_controller_.DidActivate();
EXPECT_EQ(1, reporting_controller_.ActiveReporters());
- reporting_controller_.DidSubmitCompositorFrame();
+ reporting_controller_.DidSubmitCompositorFrame(0);
EXPECT_EQ(0, reporting_controller_.ActiveReporters());
- // 4 simultaneous reporters
+ // 4 simultaneous reporters active.
SimulateActivate();
SimulateCommit();
@@ -148,9 +160,75 @@ TEST_F(CompositorFrameReportingControllerTest, ActiveReporterCounts) {
SimulateBeginImplFrame();
EXPECT_EQ(4, reporting_controller_.ActiveReporters());
- // Any additional BeginImplFrame's would be ignored
+ // Any additional BeginImplFrame's would be ignored.
SimulateBeginImplFrame();
EXPECT_EQ(4, reporting_controller_.ActiveReporters());
}
+
+TEST_F(CompositorFrameReportingControllerTest,
+ SubmittedFrameHistogramReporting) {
+ base::HistogramTester histogram_tester;
+
+ // 2 reporters active.
+ SimulateActivate();
+ SimulateBeginImplFrame();
+
+ // Submitting and Presenting the next reporter should be a missed.
+ SimulatePresentCompositorFrame();
+
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.BeginImplFrameToSendBeginMainFrame", 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.SendBeginMainFrameToCommit", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Commit", 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.EndCommitToActivation", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Activation",
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.EndActivateToSubmitCompositorFrame", 1);
+
+ // Other histograms should not be reported.
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.BeginImplFrameToSendBeginMainFrame", 0);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.SendBeginMainFrameToCommit", 0);
+ histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 0);
+ histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation",
+ 0);
+ histogram_tester.ExpectTotalCount("CompositorLatency.Activation", 0);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.EndActivateToSubmitCompositorFrame", 0);
+
+ // Submitting the next reporter will not be counted as missed.
+ // In practice this submitted frame should be considered as missed because a
+ // new BeginFrame would have been issued, which is the cause for this frame
+ // submission.
+ SimulatePresentCompositorFrame();
+ // Other histograms should not be reported.
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.BeginImplFrameToSendBeginMainFrame", 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.SendBeginMainFrameToCommit", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation",
+ 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.Activation", 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.EndActivateToSubmitCompositorFrame", 1);
+
+ // Missed frame histogram counts should not change.
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.BeginImplFrameToSendBeginMainFrame", 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.SendBeginMainFrameToCommit", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Commit", 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.EndCommitToActivation", 1);
+ histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Activation",
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "CompositorLatency.MissedFrame.EndActivateToSubmitCompositorFrame", 1);
+}
} // namespace
} // namespace cc
diff --git a/chromium/cc/scheduler/compositor_timing_history.cc b/chromium/cc/scheduler/compositor_timing_history.cc
index 6e1b3966f4f..0b509c097da 100644
--- a/chromium/cc/scheduler/compositor_timing_history.cc
+++ b/chromium/cc/scheduler/compositor_timing_history.cc
@@ -77,9 +77,6 @@ const double kPrepareTilesEstimationPercentile = 90.0;
const double kActivateEstimationPercentile = 90.0;
const double kDrawEstimationPercentile = 90.0;
-constexpr base::TimeDelta kSubmitAckWatchdogTimeout =
- base::TimeDelta::FromSeconds(8);
-
// This macro is deprecated since its bucket count uses too much bandwidth.
// It also has sub-optimal range and bucket distribution.
// TODO(brianderson): Delete this macro and associated UMAs once there is
@@ -423,7 +420,6 @@ CompositorTimingHistory::CompositorTimingHistory(
activate_duration_history_(kDurationHistorySize),
draw_duration_history_(kDurationHistorySize),
begin_main_frame_on_critical_path_(false),
- submit_ack_watchdog_enabled_(false),
uma_reporter_(CreateUMAReporter(uma_category)),
rendering_stats_instrumentation_(rendering_stats_instrumentation),
compositor_frame_reporting_controller_(
@@ -559,7 +555,6 @@ void CompositorTimingHistory::DidCreateAndInitializeLayerTreeFrameSink() {
// After we get a new output surface, we won't get a spurious
// CompositorFrameAck from the old output surface.
submit_start_time_ = base::TimeTicks();
- submit_ack_watchdog_enabled_ = false;
}
void CompositorTimingHistory::WillBeginImplFrame(
@@ -582,14 +577,6 @@ void CompositorTimingHistory::WillBeginImplFrame(
SetBeginMainFrameCommittingContinuously(false);
}
- if (submit_ack_watchdog_enabled_) {
- base::TimeDelta submit_not_acked_time_ = now - submit_start_time_;
- if (submit_not_acked_time_ >= kSubmitAckWatchdogTimeout) {
- // Only record this UMA once per submitted CompositorFrame.
- submit_ack_watchdog_enabled_ = false;
- }
- }
-
if (frame_type == viz::BeginFrameArgs::NORMAL)
uma_reporter_->AddBeginImplFrameLatency(now - frame_time);
@@ -922,11 +909,10 @@ void CompositorTimingHistory::DidDraw(
draw_start_time_ = base::TimeTicks();
}
-void CompositorTimingHistory::DidSubmitCompositorFrame() {
+void CompositorTimingHistory::DidSubmitCompositorFrame(uint32_t frame_token) {
DCHECK_EQ(base::TimeTicks(), submit_start_time_);
- compositor_frame_reporting_controller_->DidSubmitCompositorFrame();
+ compositor_frame_reporting_controller_->DidSubmitCompositorFrame(frame_token);
submit_start_time_ = Now();
- submit_ack_watchdog_enabled_ = true;
}
void CompositorTimingHistory::DidNotProduceFrame() {
@@ -937,11 +923,16 @@ void CompositorTimingHistory::DidReceiveCompositorFrameAck() {
DCHECK_NE(base::TimeTicks(), submit_start_time_);
base::TimeDelta submit_to_ack_duration = Now() - submit_start_time_;
uma_reporter_->AddSubmitToAckLatency(submit_to_ack_duration);
- if (submit_ack_watchdog_enabled_)
- submit_ack_watchdog_enabled_ = false;
submit_start_time_ = base::TimeTicks();
}
+void CompositorTimingHistory::DidPresentCompositorFrame(
+ uint32_t frame_token,
+ base::TimeTicks presentation_time) {
+ compositor_frame_reporting_controller_->DidPresentCompositorFrame(
+ frame_token, presentation_time);
+}
+
void CompositorTimingHistory::SetTreePriority(TreePriority priority) {
tree_priority_ = priority;
}
diff --git a/chromium/cc/scheduler/compositor_timing_history.h b/chromium/cc/scheduler/compositor_timing_history.h
index b5ae6cee06e..7dff0c9335c 100644
--- a/chromium/cc/scheduler/compositor_timing_history.h
+++ b/chromium/cc/scheduler/compositor_timing_history.h
@@ -88,9 +88,11 @@ class CC_EXPORT CompositorTimingHistory {
size_t main_thread_animations_count,
bool current_frame_had_raf,
bool next_frame_has_pending_raf);
- void DidSubmitCompositorFrame();
+ void DidSubmitCompositorFrame(uint32_t frame_token);
void DidNotProduceFrame();
void DidReceiveCompositorFrameAck();
+ void DidPresentCompositorFrame(uint32_t frame_token,
+ base::TimeTicks presentation_time);
void WillInvalidateOnImplSide();
void SetTreePriority(TreePriority priority);
@@ -159,9 +161,6 @@ class CC_EXPORT CompositorTimingHistory {
bool pending_tree_is_impl_side_;
- // Watchdog timers.
- bool submit_ack_watchdog_enabled_;
-
std::unique_ptr<UMAReporter> uma_reporter_;
// Owned by LayerTreeHost and is destroyed when LayerTreeHost is destroyed.
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index f9fed94544d..61073cebb06 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -115,6 +115,11 @@ void Scheduler::NotifyAnimationWorkletStateChange(AnimationWorkletState state,
ProcessScheduledActions();
}
+void Scheduler::NotifyPaintWorkletStateChange(PaintWorkletState state) {
+ state_machine_.NotifyPaintWorkletStateChange(state);
+ ProcessScheduledActions();
+}
+
void Scheduler::SetNeedsBeginMainFrame() {
state_machine_.SetNeedsBeginMainFrame();
ProcessScheduledActions();
@@ -136,8 +141,8 @@ void Scheduler::SetNeedsPrepareTiles() {
ProcessScheduledActions();
}
-void Scheduler::DidSubmitCompositorFrame() {
- compositor_timing_history_->DidSubmitCompositorFrame();
+void Scheduler::DidSubmitCompositorFrame(uint32_t frame_token) {
+ compositor_timing_history_->DidSubmitCompositorFrame(frame_token);
state_machine_.DidSubmitCompositorFrame();
// There is no need to call ProcessScheduledActions here because
@@ -191,6 +196,12 @@ void Scheduler::DidPrepareTiles() {
state_machine_.DidPrepareTiles();
}
+void Scheduler::DidPresentCompositorFrame(uint32_t frame_token,
+ base::TimeTicks presentation_time) {
+ compositor_timing_history_->DidPresentCompositorFrame(frame_token,
+ presentation_time);
+}
+
void Scheduler::DidLoseLayerTreeFrameSink() {
TRACE_EVENT0("cc", "Scheduler::DidLoseLayerTreeFrameSink");
state_machine_.DidLoseLayerTreeFrameSink();
@@ -211,7 +222,6 @@ void Scheduler::DidCreateAndInitializeLayerTreeFrameSink() {
void Scheduler::NotifyBeginMainFrameStarted(
base::TimeTicks main_thread_start_time) {
TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
- state_machine_.NotifyBeginMainFrameStarted();
compositor_timing_history_->BeginMainFrameStarted(main_thread_start_time);
}
@@ -319,7 +329,8 @@ bool Scheduler::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) {
client_->FrameIntervalUpdated(last_frame_interval_);
}
- if (ShouldDropBeginFrame(args)) {
+ // Drop the BeginFrame if we don't need one.
+ if (!state_machine_.BeginFrameNeeded()) {
TRACE_EVENT_INSTANT0("cc", "Scheduler::BeginFrameDropped",
TRACE_EVENT_SCOPE_THREAD);
// Since we don't use the BeginFrame, we may later receive the same
@@ -782,8 +793,8 @@ void Scheduler::ProcessScheduledActions() {
begin_main_frame_args_.on_critical_path,
begin_main_frame_args_.frame_time);
state_machine_.WillSendBeginMainFrame();
- // TODO(brianderson): Pass begin_main_frame_args_ directly to client.
client_->ScheduledActionSendBeginMainFrame(begin_main_frame_args_);
+ last_dispatched_begin_main_frame_args_ = begin_main_frame_args_;
break;
case SchedulerStateMachine::Action::
NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL:
@@ -801,6 +812,7 @@ void Scheduler::ProcessScheduledActions() {
state_machine_.WillCommit(commit_has_no_updates);
compositor_timing_history_->WillCommit();
client_->ScheduledActionCommit();
+ last_commit_origin_frame_args_ = last_dispatched_begin_main_frame_args_;
break;
}
case SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE:
@@ -808,6 +820,7 @@ void Scheduler::ProcessScheduledActions() {
state_machine_.WillActivate();
client_->ScheduledActionActivateSyncTree();
compositor_timing_history_->DidActivate();
+ last_activate_origin_frame_args_ = last_commit_origin_frame_args_;
break;
case SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION:
state_machine_.WillPerformImplSideInvalidation();
@@ -914,28 +927,6 @@ void Scheduler::UpdateCompositorTimingHistoryRecordingEnabled() {
state_machine_.visible());
}
-bool Scheduler::ShouldDropBeginFrame(const viz::BeginFrameArgs& args) const {
- // Drop the BeginFrame if we don't need one.
- if (!state_machine_.BeginFrameNeeded())
- return true;
-
- // Also ignore MISSED args in full-pipe mode, because a missed BeginFrame may
- // have already been completed by the DisplayScheduler. In such a case,
- // handling it now would be likely to mess up future full-pipe BeginFrames.
- // The only situation in which we can reasonably receive MISSED args is when
- // our frame sink hierarchy changes, since we always request BeginFrames in
- // full-pipe mode. If surface synchronization is also enabled, we can and
- // should use the MISSED args safely because the parent's latest
- // CompositorFrame will block its activation until we submit a new frame.
- if (args.type == viz::BeginFrameArgs::MISSED &&
- settings_.wait_for_all_pipeline_stages_before_draw &&
- !settings_.enable_surface_synchronization) {
- return true;
- }
-
- return false;
-}
-
bool Scheduler::ShouldRecoverMainLatency(
const viz::BeginFrameArgs& args,
bool can_activate_before_deadline) const {
@@ -1019,11 +1010,9 @@ bool Scheduler::CanBeginMainFrameAndActivateBeforeDeadline(
return estimated_draw_time < args.deadline;
}
-bool Scheduler::IsBeginMainFrameSentOrStarted() const {
- return (state_machine_.begin_main_frame_state() ==
- SchedulerStateMachine::BeginMainFrameState::SENT ||
- state_machine_.begin_main_frame_state() ==
- SchedulerStateMachine::BeginMainFrameState::STARTED);
+bool Scheduler::IsBeginMainFrameSent() const {
+ return state_machine_.begin_main_frame_state() ==
+ SchedulerStateMachine::BeginMainFrameState::SENT;
}
viz::BeginFrameAck Scheduler::CurrentBeginFrameAckForActiveTree() const {
diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h
index a84943e7ee8..6168d88768c 100644
--- a/chromium/cc/scheduler/scheduler.h
+++ b/chromium/cc/scheduler/scheduler.h
@@ -108,6 +108,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
void SetBeginFrameSource(viz::BeginFrameSource* source);
using AnimationWorkletState = SchedulerStateMachine::AnimationWorkletState;
+ using PaintWorkletState = SchedulerStateMachine::PaintWorkletState;
using TreeType = SchedulerStateMachine::TreeType;
// Sets whether asynchronous animation worklet mutations are running.
@@ -116,11 +117,20 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
void NotifyAnimationWorkletStateChange(AnimationWorkletState state,
TreeType tree);
+ // Sets whether asynchronous paint worklets are running. Paint worklets
+ // running should block activation of the pending tree, as it isn't fully
+ // painted until they are done.
+ void NotifyPaintWorkletStateChange(PaintWorkletState state);
+
// Set |needs_begin_main_frame_| to true, which will cause the BeginFrame
// source to be told to send BeginFrames to this client so that this client
// can send a CompositorFrame to the display compositor with appropriate
// timing.
void SetNeedsBeginMainFrame();
+ bool needs_begin_main_frame() const {
+ return state_machine_.needs_begin_main_frame();
+ }
+
// Requests a single impl frame (after the current frame if there is one
// active).
void SetNeedsOneBeginImplFrame();
@@ -143,7 +153,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
// Drawing should result in submitting a CompositorFrame to the
// LayerTreeFrameSink and then calling this.
- void DidSubmitCompositorFrame();
+ void DidSubmitCompositorFrame(uint32_t frame_token);
// The LayerTreeFrameSink acks when it is ready for a new frame which
// should result in this getting called to unblock the next draw.
void DidReceiveCompositorFrameAck();
@@ -169,6 +179,11 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
// track how long PrepareTiles takes.
void DidPrepareTiles();
+ // |DidPresentCompositorFrame| is called when the renderer receives
+ // presentation feedback.
+ void DidPresentCompositorFrame(uint32_t frame_token,
+ base::TimeTicks presentation_time);
+
void DidLoseLayerTreeFrameSink();
void DidCreateAndInitializeLayerTreeFrameSink();
@@ -216,8 +231,17 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
viz::BeginFrameAck CurrentBeginFrameAckForActiveTree() const;
+ const viz::BeginFrameArgs& last_dispatched_begin_main_frame_args() const {
+ return last_dispatched_begin_main_frame_args_;
+ }
+ const viz::BeginFrameArgs& last_activate_origin_frame_args() const {
+ return last_activate_origin_frame_args_;
+ }
+
void ClearHistory();
+ bool IsBeginMainFrameSent() const;
+
protected:
// Virtual for testing.
virtual base::TimeTicks Now() const;
@@ -244,6 +268,17 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
viz::BeginFrameAck last_begin_frame_ack_;
viz::BeginFrameArgs begin_main_frame_args_;
+ // For keeping track of the original BeginFrameArgs from the Main Thread
+ // that led to the corresponding action, i.e.:
+ // BeginMainFrame => Commit => Activate => Submit
+ // So, |last_commit_origin_frame_args_| is the BeginFrameArgs that was
+ // dispatched to the main-thread, and lead to the commit to happen.
+ // |last_activate_origin_frame_args_| is then set to that BeginFrameArgs when
+ // the committed change is activated.
+ viz::BeginFrameArgs last_dispatched_begin_main_frame_args_;
+ viz::BeginFrameArgs last_commit_origin_frame_args_;
+ viz::BeginFrameArgs last_activate_origin_frame_args_;
+
// Task posted for the deadline or drawing phase of the scheduler. This task
// can be rescheduled e.g. when the condition for the deadline is met, it is
// scheduled to run immediately.
@@ -300,7 +335,6 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
void DrawForced();
void ProcessScheduledActions();
void UpdateCompositorTimingHistoryRecordingEnabled();
- bool ShouldDropBeginFrame(const viz::BeginFrameArgs& args) const;
bool ShouldRecoverMainLatency(const viz::BeginFrameArgs& args,
bool can_activate_before_deadline) const;
bool ShouldRecoverImplLatency(const viz::BeginFrameArgs& args,
@@ -310,7 +344,6 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
base::TimeDelta bmf_to_activate_estimate,
base::TimeTicks now) const;
void AdvanceCommitStateIfPossible();
- bool IsBeginMainFrameSentOrStarted() const;
void BeginImplFrameWithDeadline(const viz::BeginFrameArgs& args);
void BeginImplFrameSynchronous(const viz::BeginFrameArgs& args);
diff --git a/chromium/cc/scheduler/scheduler_settings.cc b/chromium/cc/scheduler/scheduler_settings.cc
index 5fb52494ae3..11e3664df39 100644
--- a/chromium/cc/scheduler/scheduler_settings.cc
+++ b/chromium/cc/scheduler/scheduler_settings.cc
@@ -18,26 +18,16 @@ std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
SchedulerSettings::AsValue() const {
std::unique_ptr<base::trace_event::TracedValue> state(
new base::trace_event::TracedValue());
- state->SetBoolean("main_frame_while_submit_frame_throttled_enabled",
- main_frame_while_submit_frame_throttled_enabled);
state->SetBoolean("main_frame_before_activation_enabled",
main_frame_before_activation_enabled);
state->SetBoolean("commit_to_active_tree", commit_to_active_tree);
- state->SetBoolean("timeout_and_draw_when_animation_checkerboards",
- timeout_and_draw_when_animation_checkerboards);
state->SetInteger("maximum_number_of_failed_draws_before_draw_is_forced",
maximum_number_of_failed_draws_before_draw_is_forced);
state->SetBoolean("using_synchronous_renderer_compositor",
using_synchronous_renderer_compositor);
- state->SetInteger("background_frame_interval",
- background_frame_interval.InMicroseconds());
state->SetBoolean("enable_latency_recovery", enable_latency_recovery);
state->SetBoolean("wait_for_all_pipeline_stages_before_draw",
wait_for_all_pipeline_stages_before_draw);
- state->SetBoolean("enable_surface_synchronization",
- enable_surface_synchronization);
- state->SetBoolean("compositor_threaded_scrollbar_scrolling",
- compositor_threaded_scrollbar_scrolling);
return std::move(state);
}
diff --git a/chromium/cc/scheduler/scheduler_settings.h b/chromium/cc/scheduler/scheduler_settings.h
index 318820844fa..86230194b63 100644
--- a/chromium/cc/scheduler/scheduler_settings.h
+++ b/chromium/cc/scheduler/scheduler_settings.h
@@ -26,18 +26,34 @@ class CC_EXPORT SchedulerSettings {
SchedulerSettings(const SchedulerSettings& other);
~SchedulerSettings();
- bool main_frame_while_submit_frame_throttled_enabled = false;
+ // Whether a BeginMainFrame should be issued while there is a pending-tree
+ // still waiting to be activated. This is disabled by default for the UI
+ // compositor, and enabled for renderers (unless there are too few cores).
bool main_frame_before_activation_enabled = false;
+
+ // Whether commits should happen directly to the active tree, skipping the
+ // pending tree. This is turned on only for the UI compositor (and in some
+ // tests).
bool commit_to_active_tree = false;
- bool timeout_and_draw_when_animation_checkerboards = true;
+
+ // This is enabled for android-webview.
bool using_synchronous_renderer_compositor = false;
+
+ // This is used to determine whether some begin-frames should be skipped (both
+ // in the main-thread and the compositor-thread) if previous frames have had
+ // high latency.
+ // It is enabled by default on desktop platforms, and has been recently
+ // disabled by default on android. It may be disabled on all platforms. See
+ // more in https://crbug.com/933846
bool enable_latency_recovery = true;
+
+ // Turning this on effectively disables pipelining of compositor frame
+ // production stages by waiting for each stage to complete before producing
+ // the frame. Turning this on also disables latency-recovery. This is enabled
+ // for headless-mode and some tests, and disabled elsewhere by default.
bool wait_for_all_pipeline_stages_before_draw = false;
- bool enable_surface_synchronization = false;
- bool compositor_threaded_scrollbar_scrolling = false;
int maximum_number_of_failed_draws_before_draw_is_forced = 3;
- base::TimeDelta background_frame_interval = base::TimeDelta::FromSeconds(1);
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
};
diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc
index 29479c7dd3c..7ec7152365a 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine.cc
@@ -79,8 +79,6 @@ const char* SchedulerStateMachine::BeginMainFrameStateToString(
return "BeginMainFrameState::IDLE";
case BeginMainFrameState::SENT:
return "BeginMainFrameState::SENT";
- case BeginMainFrameState::STARTED:
- return "BeginMainFrameState::STARTED";
case BeginMainFrameState::READY_TO_COMMIT:
return "BeginMainFrameState::READY_TO_COMMIT";
}
@@ -241,6 +239,8 @@ void SchedulerStateMachine::AsValueInto(
processing_animation_worklets_for_active_tree_);
state->SetBoolean("processing_animation_worklets_for_pending_tree",
processing_animation_worklets_for_pending_tree_);
+ state->SetBoolean("processing_paint_worklets_for_pending_tree",
+ processing_paint_worklets_for_pending_tree_);
state->EndDictionary();
}
@@ -379,6 +379,15 @@ bool SchedulerStateMachine::ShouldActivateSyncTree() const {
if (active_tree_needs_first_draw_)
return false;
+ // Delay pending tree activation until paint worklets have completed painting
+ // the pending tree. This must occur before the |ShouldAbortCurrentFrame|
+ // check as we cannot have an unpainted active tree.
+ //
+ // Note that paint worklets continue to paint when the page is not visible, so
+ // any abort will eventually happen when they complete.
+ if (processing_paint_worklets_for_pending_tree_)
+ return false;
+
if (ShouldAbortCurrentFrame())
return true;
@@ -537,18 +546,16 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (!HasInitializedLayerTreeFrameSink())
return false;
- if (!settings_.main_frame_while_submit_frame_throttled_enabled) {
- // Throttle the BeginMainFrames on CompositorFrameAck unless we just
- // submitted a frame to potentially improve impl-thread latency over
- // main-thread throughput.
- // TODO(brianderson): Remove this restriction to improve throughput or
- // make it conditional on ImplLatencyTakesPriority.
- bool just_submitted_in_deadline =
- begin_impl_frame_state_ == BeginImplFrameState::INSIDE_DEADLINE &&
- did_submit_in_last_frame_;
- if (IsDrawThrottled() && !just_submitted_in_deadline)
- return false;
- }
+ // Throttle the BeginMainFrames on CompositorFrameAck unless we just
+ // submitted a frame to potentially improve impl-thread latency over
+ // main-thread throughput.
+ // TODO(brianderson): Remove this restriction to improve throughput or
+ // make it conditional on ImplLatencyTakesPriority.
+ bool just_submitted_in_deadline =
+ begin_impl_frame_state_ == BeginImplFrameState::INSIDE_DEADLINE &&
+ did_submit_in_last_frame_;
+ if (IsDrawThrottled() && !just_submitted_in_deadline)
+ return false;
if (skip_next_begin_main_frame_to_reduce_latency_)
return false;
@@ -710,8 +717,7 @@ bool SchedulerStateMachine::ShouldDeferInvalidatingForMainFrame() const {
return true;
// If the main frame was already sent, wait for the main thread to respond.
- if (begin_main_frame_state_ == BeginMainFrameState::SENT ||
- begin_main_frame_state_ == BeginMainFrameState::STARTED)
+ if (begin_main_frame_state_ == BeginMainFrameState::SENT)
return true;
// If the main thread committed during the last frame, i.e. it was not
@@ -847,6 +853,11 @@ void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) {
}
void SchedulerStateMachine::WillActivate() {
+ // We cannot activate the pending tree while paint worklets are still being
+ // processed; the pending tree *must* be fully painted before it can ever be
+ // activated because we cannot paint the active tree.
+ DCHECK(!processing_paint_worklets_for_pending_tree_);
+
if (layer_tree_frame_sink_state_ ==
LayerTreeFrameSinkState::WAITING_FOR_FIRST_ACTIVATION)
layer_tree_frame_sink_state_ = LayerTreeFrameSinkState::ACTIVE;
@@ -906,8 +917,7 @@ void SchedulerStateMachine::DidDrawInternal(DrawResult draw_result) {
if (consecutive_checkerboard_animations_ >=
settings_.maximum_number_of_failed_draws_before_draw_is_forced &&
- forced_redraw_state_ == ForcedRedrawOnTimeoutState::IDLE &&
- settings_.timeout_and_draw_when_animation_checkerboards) {
+ forced_redraw_state_ == ForcedRedrawOnTimeoutState::IDLE) {
// We need to force a draw, but it doesn't make sense to do this until
// we've committed and have new textures.
forced_redraw_state_ = ForcedRedrawOnTimeoutState::WAITING_FOR_COMMIT;
@@ -1134,8 +1144,7 @@ void SchedulerStateMachine::OnBeginImplFrameIdle() {
main_thread_missed_last_deadline_ =
CommitPending() || has_pending_tree_ || active_tree_needs_first_draw_;
main_thread_failed_to_respond_last_deadline_ =
- begin_main_frame_state_ == BeginMainFrameState::SENT ||
- begin_main_frame_state_ == BeginMainFrameState::STARTED;
+ begin_main_frame_state_ == BeginMainFrameState::SENT;
// If we're entering a state where we won't get BeginFrames set all the
// funnels so that we don't perform any actions that we shouldn't.
@@ -1364,7 +1373,7 @@ void SchedulerStateMachine::SetNeedsOneBeginImplFrame() {
}
void SchedulerStateMachine::NotifyReadyToCommit() {
- DCHECK_EQ(begin_main_frame_state_, BeginMainFrameState::STARTED)
+ DCHECK_EQ(begin_main_frame_state_, BeginMainFrameState::SENT)
<< AsValue()->ToString();
begin_main_frame_state_ = BeginMainFrameState::READY_TO_COMMIT;
// In commit_to_active_tree mode, commit should happen right after BeginFrame,
@@ -1374,7 +1383,7 @@ void SchedulerStateMachine::NotifyReadyToCommit() {
}
void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) {
- DCHECK_EQ(begin_main_frame_state_, BeginMainFrameState::STARTED);
+ DCHECK_EQ(begin_main_frame_state_, BeginMainFrameState::SENT);
// If the main thread aborted, it doesn't matter if the main thread missed
// the last deadline since it didn't have an update anyway.
@@ -1415,6 +1424,12 @@ void SchedulerStateMachine::DidLoseLayerTreeFrameSink() {
}
bool SchedulerStateMachine::NotifyReadyToActivate() {
+ // It is not valid for clients to try and activate the pending tree whilst
+ // paint worklets are still being processed; the pending tree *must* be fully
+ // painted before it can ever be activated (even if e.g. it is not visible),
+ // because we cannot paint the active tree.
+ DCHECK(!processing_paint_worklets_for_pending_tree_);
+
if (!has_pending_tree_ || pending_tree_is_ready_for_activation_)
return false;
@@ -1448,6 +1463,16 @@ void SchedulerStateMachine::NotifyAnimationWorkletStateChange(
}
}
+void SchedulerStateMachine::NotifyPaintWorkletStateChange(
+ PaintWorkletState state) {
+ bool processing_paint_worklets_for_pending_tree =
+ (state == PaintWorkletState::PROCESSING);
+ DCHECK_NE(processing_paint_worklets_for_pending_tree,
+ processing_paint_worklets_for_pending_tree_);
+ processing_paint_worklets_for_pending_tree_ =
+ processing_paint_worklets_for_pending_tree;
+}
+
void SchedulerStateMachine::DidCreateAndInitializeLayerTreeFrameSink() {
DCHECK_EQ(layer_tree_frame_sink_state_, LayerTreeFrameSinkState::CREATING);
layer_tree_frame_sink_state_ =
@@ -1464,11 +1489,6 @@ void SchedulerStateMachine::DidCreateAndInitializeLayerTreeFrameSink() {
main_thread_missed_last_deadline_ = false;
}
-void SchedulerStateMachine::NotifyBeginMainFrameStarted() {
- DCHECK_EQ(begin_main_frame_state_, BeginMainFrameState::SENT);
- begin_main_frame_state_ = BeginMainFrameState::STARTED;
-}
-
bool SchedulerStateMachine::HasInitializedLayerTreeFrameSink() const {
switch (layer_tree_frame_sink_state_) {
case LayerTreeFrameSinkState::NONE:
diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h
index 091f1af3b7c..198e2ff1749 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.h
+++ b/chromium/cc/scheduler/scheduler_state_machine.h
@@ -88,13 +88,15 @@ class CC_EXPORT SchedulerStateMachine {
BeginImplFrameDeadlineMode mode);
enum class BeginMainFrameState {
- IDLE,
- SENT,
- STARTED,
- READY_TO_COMMIT,
+ IDLE, // A new BeginMainFrame can start.
+ SENT, // A BeginMainFrame has already been issued.
+ READY_TO_COMMIT, // A previously issued BeginMainFrame has been processed,
+ // and is ready to commit.
};
static const char* BeginMainFrameStateToString(BeginMainFrameState state);
+ // When a redraw is forced, it goes through a complete commit -> activation ->
+ // draw cycle. Until a redraw has been forced, it remains in IDLE state.
enum class ForcedRedrawOnTimeoutState {
IDLE,
WAITING_FOR_COMMIT,
@@ -109,9 +111,7 @@ class CC_EXPORT SchedulerStateMachine {
}
bool CommitPending() const {
- return begin_main_frame_state_ == BeginMainFrameState::SENT ||
- begin_main_frame_state_ == BeginMainFrameState::STARTED ||
- begin_main_frame_state_ == BeginMainFrameState::READY_TO_COMMIT;
+ return begin_main_frame_state_ != BeginMainFrameState::IDLE;
}
bool NewActiveTreeLikely() const {
@@ -271,9 +271,6 @@ class CC_EXPORT SchedulerStateMachine {
// frame sink is not ready to receive frames.
void SetSkipDraw(bool skip);
- // Indicates that scheduled BeginMainFrame is started.
- void NotifyBeginMainFrameStarted();
-
// Indicates that the pending tree is ready for activation. Returns whether
// the notification received updated the state for the current pending tree,
// if any.
@@ -283,6 +280,7 @@ class CC_EXPORT SchedulerStateMachine {
void NotifyReadyToDraw();
enum class AnimationWorkletState { PROCESSING, IDLE };
+ enum class PaintWorkletState { PROCESSING, IDLE };
enum class TreeType { ACTIVE, PENDING };
// Indicates if currently processing animation worklets for the active or
@@ -291,6 +289,11 @@ class CC_EXPORT SchedulerStateMachine {
void NotifyAnimationWorkletStateChange(AnimationWorkletState state,
TreeType tree);
+ // Sets whether asynchronous paint worklets are running. Paint worklets
+ // running should block activation of the pending tree, as it isn't fully
+ // painted until they are done.
+ void NotifyPaintWorkletStateChange(PaintWorkletState state);
+
void SetNeedsImplSideInvalidation(bool needs_first_draw_on_activation);
bool has_pending_tree() const { return has_pending_tree_; }
@@ -377,6 +380,9 @@ class CC_EXPORT SchedulerStateMachine {
LayerTreeFrameSinkState::NONE;
BeginImplFrameState begin_impl_frame_state_ = BeginImplFrameState::IDLE;
BeginMainFrameState begin_main_frame_state_ = BeginMainFrameState::IDLE;
+
+ // A redraw is forced when too many checkerboarded-frames are produced during
+ // an animation.
ForcedRedrawOnTimeoutState forced_redraw_state_ =
ForcedRedrawOnTimeoutState::IDLE;
@@ -451,6 +457,9 @@ class CC_EXPORT SchedulerStateMachine {
// Indicates if an aysnc mutation cycle is in-flight or queued for the pending
// tree. Only one can be running or queued at any time.
bool processing_animation_worklets_for_pending_tree_ = false;
+ // Indicates if asychronous paint worklet painting is ongoing for the pending
+ // tree. During this time we should not activate the pending tree.
+ bool processing_paint_worklets_for_pending_tree_ = false;
// Set to true if the main thread fails to respond with a commit or abort the
// main frame before the draw deadline on the previous impl frame.
diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
index 676b83ee4ae..9e1adff48c4 100644
--- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include "base/test/gtest_util.h"
#include "base/trace_event/trace_event.h"
#include "cc/scheduler/scheduler.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
@@ -74,7 +75,6 @@ const SchedulerStateMachine::BeginImplFrameState all_begin_impl_frame_states[] =
const SchedulerStateMachine::BeginMainFrameState begin_main_frame_states[] = {
SchedulerStateMachine::BeginMainFrameState::IDLE,
SchedulerStateMachine::BeginMainFrameState::SENT,
- SchedulerStateMachine::BeginMainFrameState::STARTED,
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT};
// Exposes the protected state fields of the SchedulerStateMachine for testing
@@ -450,7 +450,6 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
@@ -468,7 +467,6 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
// Verify the pending commit doesn't overwrite the pending
// tree until the pending tree has been activated.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
@@ -561,7 +559,6 @@ TEST(SchedulerStateMachineTest, FailedDrawForMissingHighResNeedsCommit) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
// Finish the commit and activation.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
@@ -610,7 +607,6 @@ TEST(SchedulerStateMachineTest,
// Finish the commit. Note, we should not yet be forcing a draw, but should
// continue the commit as usual.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
@@ -924,7 +920,6 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -953,7 +948,6 @@ TEST(SchedulerStateMachineTest, TestSetNeedsBeginMainFrameIsNotLost) {
EXPECT_TRUE(state.NeedsCommit());
// Let the frame finish.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
@@ -1012,7 +1006,6 @@ TEST(SchedulerStateMachineTest, TestFullCycle) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
// Tell the scheduler the frame finished.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
@@ -1053,7 +1046,6 @@ TEST(SchedulerStateMachineTest, CommitWithoutDrawWithPendingTree) {
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -1066,7 +1058,6 @@ TEST(SchedulerStateMachineTest, CommitWithoutDrawWithPendingTree) {
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
}
@@ -1085,7 +1076,6 @@ TEST(SchedulerStateMachineTest, DontCommitWithoutDrawWithoutPendingTree) {
state.OnBeginImplFrame(0, 10, kAnimateOnly);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -1110,7 +1100,6 @@ TEST(SchedulerStateMachineTest, AbortedMainFrameDoesNotResetPendingTree) {
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
@@ -1126,7 +1115,6 @@ TEST(SchedulerStateMachineTest, AbortedMainFrameDoesNotResetPendingTree) {
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.has_pending_tree());
- state.NotifyBeginMainFrameStarted();
state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.has_pending_tree());
@@ -1139,7 +1127,6 @@ TEST(SchedulerStateMachineTest, AbortedMainFrameDoesNotResetPendingTree) {
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.has_pending_tree());
@@ -1172,7 +1159,6 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
// Tell the scheduler the frame finished.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
@@ -1211,7 +1197,6 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) {
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -1252,7 +1237,6 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
// Tell the scheduler the frame finished.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
@@ -1351,7 +1335,6 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) {
// Become invisible and abort BeginMainFrame.
state.SetVisible(false);
- state.NotifyBeginMainFrameStarted();
state.BeginMainFrameAborted(CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
// NeedsCommit should now be true again because we never actually did a
@@ -1407,7 +1390,6 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) {
// Abort the commit, true means that the BeginMainFrame was sent but there
// was no work to do on the main thread.
- state.NotifyBeginMainFrameStarted();
state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
// NeedsCommit should now be false because the commit was actually handled.
@@ -1535,7 +1517,6 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
// Finish the commit, which should make the surface active.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_EQ(state.layer_tree_frame_sink_state(),
@@ -1585,7 +1566,6 @@ TEST(SchedulerStateMachineTest,
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
// Activate so we need the first draw
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -1631,7 +1611,6 @@ TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
// Finish the frame, commit and activate.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -1689,7 +1668,6 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
// Finish the frame, and commit and activate.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -1724,7 +1702,6 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
@@ -1770,7 +1747,6 @@ TEST(SchedulerStateMachineTest,
// Cause a lost context.
state.DidLoseLayerTreeFrameSink();
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
@@ -1837,7 +1813,6 @@ TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
// After the commit completes, activation and draw happen immediately
// because we are not visible.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
@@ -1862,7 +1837,6 @@ TEST(SchedulerStateMachineTest,
// After the commit completes, activation and draw happen immediately
// because we are not visible.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_TRUE(state.ShouldAbortCurrentFrame());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
@@ -1995,7 +1969,6 @@ TEST(SchedulerStateMachineTest,
// Since only the scroll offset changed, the main thread will abort the
// commit.
- state.NotifyBeginMainFrameStarted();
state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
// Since the commit was aborted, we should draw right away instead of waiting
@@ -2008,7 +1981,6 @@ void FinishPreviousCommitAndDrawWithoutExitingDeadline(
// Gross, but allows us to use macros below.
StateMachine& state = *state_ptr;
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
@@ -2201,7 +2173,6 @@ TEST(SchedulerStateMachineTest,
// Abort the commit, since that is what we expect the main thread to do if the
// LayerTreeFrameSink was lost due to a synchronous call from the main thread
// to release the LayerTreeFrameSink.
- state.NotifyBeginMainFrameStarted();
state.BeginMainFrameAborted(
CommitEarlyOutReason::ABORTED_LAYER_TREE_FRAME_SINK_LOST);
@@ -2283,7 +2254,6 @@ TEST(SchedulerStateMachineTest,
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -2311,7 +2281,6 @@ TEST(SchedulerStateMachineTest,
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
@@ -2373,7 +2342,6 @@ TEST(SchedulerStateMachineTest, NoImplSideInvalidationUntilFrameSinkActive) {
// No impl side invalidation because we're still waiting for first commit.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
@@ -2416,7 +2384,6 @@ TEST(SchedulerStateMachineTest, ImplSideInvalidationWhenPendingTreeExists) {
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
@@ -2456,7 +2423,6 @@ TEST(SchedulerStateMachineTest, ImplSideInvalidationWhileReadyToCommit) {
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
// Request an impl-side invalidation after we are ready to commit. The
@@ -2513,7 +2479,6 @@ TEST(SchedulerStateMachineTest, ImplSideInvalidationsThrottledOnDraw) {
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -2595,7 +2560,6 @@ TEST(SchedulerStateMachineTest, TestFullPipelineMode) {
state.CurrentBeginImplFrameDeadlineMode());
// Tell the scheduler the frame finished.
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
@@ -2686,7 +2650,6 @@ TEST(SchedulerStateMachineTest, TestFullPipelineMode) {
state.CurrentBeginImplFrameDeadlineMode());
// Abort commit and ensure that we don't block anymore.
- state.NotifyBeginMainFrameStarted();
state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
@@ -2716,7 +2679,6 @@ TEST(SchedulerStateMachineTest, AllowSkippingActiveTreeFirstDraws) {
state.OnBeginImplFrame(0, 2, kAnimateOnly);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
@@ -2736,7 +2698,6 @@ TEST(SchedulerStateMachineTest, DelayDrawIfAnimationWorkletsPending) {
state.OnBeginImplFrame(0, 10, kAnimateOnly);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyReadyToActivate();
@@ -2801,7 +2762,6 @@ TEST(SchedulerStateMachineTest, BlockActivationIfAnimationWorkletsPending) {
state.OnBeginImplFrame(0, 10, kAnimateOnly);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
- state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
state.NotifyAnimationWorkletStateChange(
@@ -2815,5 +2775,57 @@ TEST(SchedulerStateMachineTest, BlockActivationIfAnimationWorkletsPending) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
}
+TEST(SchedulerStateMachineTest, BlockActivationIfPaintWorkletsPending) {
+ SchedulerSettings settings;
+ StateMachine state(settings);
+ SET_UP_STATE(state);
+
+ state.SetNeedsBeginMainFrame();
+ state.OnBeginImplFrame(0, 10, kAnimateOnly);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
+
+ // Post-commit, we start working on PaintWorklets. It is not valid to activate
+ // until they are done.
+ state.NotifyPaintWorkletStateChange(
+ SchedulerStateMachine::PaintWorkletState::PROCESSING);
+ // We (correctly) cannot call state.NotifyReadyToActivate() here as it hits a
+ // DCHECK because PaintWorklets are ongoing.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
+ state.NotifyPaintWorkletStateChange(
+ SchedulerStateMachine::PaintWorkletState::IDLE);
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
+}
+
+TEST(SchedulerStateMachineTest,
+ BlockActivationIfPaintWorkletsPendingEvenWhenAbortingFrame) {
+ SchedulerSettings settings;
+ StateMachine state(settings);
+ SET_UP_STATE(state);
+
+ state.SetNeedsBeginMainFrame();
+ state.OnBeginImplFrame(0, 10, kAnimateOnly);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
+
+ // Even if we are aborting the frame, we must paint the pending tree before we
+ // activate it (because we cannot have an unpainted active tree).
+ state.NotifyPaintWorkletStateChange(
+ SchedulerStateMachine::PaintWorkletState::PROCESSING);
+ state.SetVisible(false);
+ ASSERT_TRUE(state.ShouldAbortCurrentFrame());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
+ state.NotifyPaintWorkletStateChange(
+ SchedulerStateMachine::PaintWorkletState::IDLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc
index 2f5deee74de..46882a54cc4 100644
--- a/chromium/cc/scheduler/scheduler_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_unittest.cc
@@ -163,7 +163,7 @@ class FakeSchedulerClient : public SchedulerClient,
draw_will_happen_ && swap_will_happen_if_draw_happens_;
if (swap_will_happen) {
last_begin_frame_ack_ = scheduler_->CurrentBeginFrameAckForActiveTree();
- scheduler_->DidSubmitCompositorFrame();
+ scheduler_->DidSubmitCompositorFrame(0);
if (automatic_ack_)
scheduler_->DidReceiveCompositorFrameAck();
@@ -2153,126 +2153,6 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) {
"ScheduledActionDrawIfPossible");
}
-TEST_F(
- SchedulerTest,
- Deadlock_CommitMakesProgressWhileSwapTrottledAndActiveTreeNeedsFirstDraw) {
- // NPAPI plugins on Windows block the Browser UI thread on the Renderer main
- // thread. This prevents the scheduler from receiving any pending swap acks.
-
- scheduler_settings_.main_frame_while_submit_frame_throttled_enabled = true;
- SetUpScheduler(EXTERNAL_BFS);
-
- // Disables automatic swap acks so this test can force swap ack throttling
- // to simulate a blocked Browser ui thread.
- client_->SetAutomaticSubmitCompositorFrameAck(false);
-
- // Get a new active tree in main-thread high latency mode and put us
- // in a swap throttled state.
- client_->Reset();
- EXPECT_FALSE(scheduler_->CommitPending());
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->SetNeedsRedraw();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit();
- scheduler_->NotifyReadyToActivate();
- EXPECT_FALSE(scheduler_->CommitPending());
- EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
- "ScheduledActionSendBeginMainFrame",
- "ScheduledActionDrawIfPossible", "ScheduledActionCommit",
- "ScheduledActionActivateSyncTree");
-
- // Make sure that we can finish the next commit even while swap throttled.
- client_->Reset();
- EXPECT_FALSE(scheduler_->CommitPending());
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit();
- scheduler_->NotifyReadyToActivate();
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionCommit");
-
- // Make sure we do not send a BeginMainFrame while swap throttled and
- // we have both a pending tree and an active tree.
- client_->Reset();
- EXPECT_FALSE(scheduler_->CommitPending());
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_FALSE(scheduler_->CommitPending());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("WillBeginImplFrame");
-}
-
-TEST_F(
- SchedulerTest,
- CommitMakesProgressWhenIdleAndHasPendingTreeAndActiveTreeNeedsFirstDraw) {
- // This verifies we don't block commits longer than we need to
- // for performance reasons - not deadlock reasons.
-
- // Since we are simulating a long commit, set up a client with draw duration
- // estimates that prevent skipping main frames to get to low latency mode.
- scheduler_settings_.main_frame_while_submit_frame_throttled_enabled = true;
- scheduler_settings_.main_frame_before_activation_enabled = true;
- SetUpScheduler(EXTERNAL_BFS);
-
- // Disables automatic swap acks so this test can force swap ack throttling
- // to simulate a blocked Browser ui thread.
- client_->SetAutomaticSubmitCompositorFrameAck(false);
-
- // Start a new commit in main-thread high latency mode and hold off on
- // activation.
- client_->Reset();
- EXPECT_FALSE(scheduler_->CommitPending());
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->SetNeedsRedraw();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- scheduler_->DidReceiveCompositorFrameAck();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit();
- EXPECT_FALSE(scheduler_->CommitPending());
- EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
- "ScheduledActionSendBeginMainFrame",
- "ScheduledActionDrawIfPossible", "ScheduledActionCommit");
-
- // Start another commit while we still have an active tree.
- client_->Reset();
- EXPECT_FALSE(scheduler_->CommitPending());
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->SetNeedsRedraw();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- scheduler_->DidReceiveCompositorFrameAck();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionDrawIfPossible");
-
- // Can't commit yet because there's still a pending tree.
- client_->Reset();
- scheduler_->NotifyReadyToCommit();
- EXPECT_NO_ACTION();
-
- // Activate the pending tree, which also unblocks the commit immediately
- // while we are in an idle state.
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree", "ScheduledActionCommit");
-}
-
void SchedulerTest::BeginFramesNotFromClient(BeginFrameSourceType bfs_type) {
SetUpScheduler(bfs_type);
@@ -4112,38 +3992,8 @@ TEST_F(SchedulerTest, CriticalBeginMainFrameToActivateIsFast) {
EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
}
-TEST_F(SchedulerTest, WaitForAllPipelineStagesSkipsMissedBeginFrames) {
- scheduler_settings_.wait_for_all_pipeline_stages_before_draw = true;
- client_ = std::make_unique<FakeSchedulerClient>();
- CreateScheduler(EXTERNAL_BFS);
-
- // Initialize frame sink so that state machine Scheduler and state machine
- // need BeginFrames.
- scheduler_->SetVisible(true);
- scheduler_->SetCanDraw(true);
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
- client_->Reset();
- scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
-
- base::TimeDelta interval = base::TimeDelta::FromMilliseconds(16);
- task_runner_->AdvanceMockTickClock(interval);
- viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0u, 1u, task_runner_->NowTicks(),
- task_runner_->NowTicks() + interval, interval,
- viz::BeginFrameArgs::MISSED);
- fake_external_begin_frame_source_->TestOnBeginFrame(args);
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
-}
-
-TEST_F(
- SchedulerTest,
- WaitForAllPipelineStagesUsesMissedBeginFramesWithSurfaceSynchronization) {
+TEST_F(SchedulerTest, WaitForAllPipelineStagesUsesMissedBeginFrames) {
scheduler_settings_.wait_for_all_pipeline_stages_before_draw = true;
- scheduler_settings_.enable_surface_synchronization = true;
client_ = std::make_unique<FakeSchedulerClient>();
CreateScheduler(EXTERNAL_BFS);
@@ -4173,7 +4023,6 @@ TEST_F(
TEST_F(SchedulerTest, WaitForAllPipelineStagesAlwaysObservesBeginFrames) {
scheduler_settings_.wait_for_all_pipeline_stages_before_draw = true;
- scheduler_settings_.enable_surface_synchronization = true;
client_ = std::make_unique<FakeSchedulerClient>();
CreateScheduler(EXTERNAL_BFS);
diff --git a/chromium/cc/tiles/checker_image_tracker.cc b/chromium/cc/tiles/checker_image_tracker.cc
index 6eda401d7a5..c31c7b5e3e9 100644
--- a/chromium/cc/tiles/checker_image_tracker.cc
+++ b/chromium/cc/tiles/checker_image_tracker.cc
@@ -135,8 +135,7 @@ CheckerImageTracker::CheckerImageTracker(ImageController* image_controller,
: image_controller_(image_controller),
client_(client),
enable_checker_imaging_(enable_checker_imaging),
- min_image_bytes_to_checker_(min_image_bytes_to_checker),
- weak_factory_(this) {}
+ min_image_bytes_to_checker_(min_image_bytes_to_checker) {}
CheckerImageTracker::~CheckerImageTracker() = default;
diff --git a/chromium/cc/tiles/checker_image_tracker.h b/chromium/cc/tiles/checker_image_tracker.h
index ee5578f8fef..7628689915b 100644
--- a/chromium/cc/tiles/checker_image_tracker.h
+++ b/chromium/cc/tiles/checker_image_tracker.h
@@ -208,7 +208,7 @@ class CC_EXPORT CheckerImageTracker {
base::flat_map<PaintImage::Id, PaintImage::DecodingMode> decoding_mode_map_;
- base::WeakPtrFactory<CheckerImageTracker> weak_factory_;
+ base::WeakPtrFactory<CheckerImageTracker> weak_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/tiles/decoded_image_tracker.cc b/chromium/cc/tiles/decoded_image_tracker.cc
index 5db3f198b6d..a7aa6b497ad 100644
--- a/chromium/cc/tiles/decoded_image_tracker.cc
+++ b/chromium/cc/tiles/decoded_image_tracker.cc
@@ -28,8 +28,7 @@ DecodedImageTracker::DecodedImageTracker(
scoped_refptr<base::SequencedTaskRunner> task_runner)
: image_controller_(controller),
task_runner_(std::move(task_runner)),
- tick_clock_(base::DefaultTickClock::GetInstance()),
- weak_ptr_factory_(this) {
+ tick_clock_(base::DefaultTickClock::GetInstance()) {
DCHECK(image_controller_);
}
diff --git a/chromium/cc/tiles/decoded_image_tracker.h b/chromium/cc/tiles/decoded_image_tracker.h
index 4803dfa3a2e..c3bf49793bc 100644
--- a/chromium/cc/tiles/decoded_image_tracker.h
+++ b/chromium/cc/tiles/decoded_image_tracker.h
@@ -93,7 +93,7 @@ class CC_EXPORT DecodedImageTracker {
// Defaults to base::TimeTicks::Now(), but overrideable for testing.
const base::TickClock* tick_clock_;
- base::WeakPtrFactory<DecodedImageTracker> weak_ptr_factory_;
+ base::WeakPtrFactory<DecodedImageTracker> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc
index 30ce3e45e4d..78dd9c6b720 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache.cc
@@ -8,7 +8,9 @@
#include "base/auto_reset.h"
#include "base/bind.h"
+#include "base/containers/span.h"
#include "base/debug/alias.h"
+#include "base/feature_list.h"
#include "base/hash/hash.h"
#include "base/memory/discardable_memory_allocator.h"
#include "base/metrics/histogram_macros.h"
@@ -18,7 +20,6 @@
#include "base/trace_event/memory_dump_manager.h"
#include "cc/base/devtools_instrumentation.h"
#include "cc/base/histograms.h"
-#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/raster/scoped_grcontext_access.h"
#include "cc/raster/tile_task.h"
#include "cc/tiles/mipmap_util.h"
@@ -26,6 +27,8 @@
#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/common/sync_token.h"
+#include "gpu/config/gpu_finch_features.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -33,6 +36,8 @@
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/GrTexture.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/skia_util.h"
#include "ui/gl/trace_util.h"
@@ -160,6 +165,16 @@ bool ShouldGenerateMips(const DrawImage& draw_image,
return false;
}
+// This helper method takes in
+// - |yuva_size_info| corresponding to the plane dimensions of a YUV image
+// - |info| indicating SkAlphaType and SkColorSpace per plane (though the final
+// image color space is currently indicated through other means at creation
+// of the YUV SkImage)
+// - |memory_ptr| pointing to sufficient contiguous memory for the planes
+//
+// It then sets each SkPixmap to have the dimensions specified by its respective
+// SkYUVAIndex within |yuva_size_info| and to point to bytes in memory at
+// |planes[index]|.
void SetYuvPixmapsFromSizeInfo(SkPixmap* pixmap_y,
SkPixmap* pixmap_u,
SkPixmap* pixmap_v,
@@ -189,6 +204,41 @@ void SetYuvPixmapsFromSizeInfo(SkPixmap* pixmap_y,
v_decode_info.minRowBytes());
}
+// Helper method to fill in |scaled_u_size| and |scaled_v_size| by computing
+// the mip level for each plane given the final raster dimensions and the
+// unscaled U and V plane sizes. Also takes in |draw_image| to compute the Y
+// plane mip level and DCHECK that the computed mip levels for U and V are
+// reasonable.
+//
+// TODO(crbug.com/915972): Assumes 420 subsampling and DCHECKs the size ratios.
+void ComputeMippedUVPlaneSizes(const gfx::Size& target_raster_size,
+ const gfx::Size& unscaled_u_size,
+ const gfx::Size& unscaled_v_size,
+ const DrawImage& draw_image,
+ gfx::Size* scaled_u_size,
+ gfx::Size* scaled_v_size) {
+ DCHECK(scaled_u_size);
+ DCHECK(scaled_v_size);
+ DCHECK_EQ(unscaled_u_size, unscaled_v_size);
+ DCHECK_EQ((draw_image.paint_image().width() + 1) / 2,
+ unscaled_u_size.width());
+ const int uv_mip_level =
+ MipMapUtil::GetLevelForSize(unscaled_u_size, target_raster_size);
+ // Check that the chroma planes do not shrink *more* than the luma.
+ // At least for YUV420, they will shrink at most one mip level below luma,
+ // which avoids blurriness.
+ DCHECK_GE(uv_mip_level, 0);
+ if (CalculateUploadScaleMipLevel(draw_image) == 0) {
+ // If Y is not scaled, then U and V shouldn't be either.
+ DCHECK_EQ(uv_mip_level, 0);
+ } else {
+ DCHECK_EQ(CalculateUploadScaleMipLevel(draw_image) - 1, uv_mip_level);
+ }
+
+ *scaled_u_size = MipMapUtil::GetSizeForLevel(unscaled_u_size, uv_mip_level);
+ *scaled_v_size = *scaled_u_size;
+}
+
// Draws and scales the provided |draw_image| into the |target_pixmap|. If the
// draw/scale can be done directly, calls directly into PaintImage::Decode.
// if not, decodes to a compatible temporary pixmap and then converts that into
@@ -316,23 +366,34 @@ bool DrawAndScaleImage(const DrawImage& draw_image,
&unscaled_pixmap_v, yuva_size_info, planes,
decode_info, decode_pixmap.writable_addr());
- // Assumes YUV420 and splits decode_pixmap into pixmaps for each plane.
- // TODO(crbug.com/915972): Fix this assumption.
const SkImageInfo y_info_scaled = info.makeColorType(kGray_8_SkColorType);
- const size_t uv_width_scaled = (y_info_scaled.width() + 1) / 2;
- const size_t uv_height_scaled = (y_info_scaled.height() + 1) / 2;
- const SkImageInfo uv_info_scaled =
- y_info_scaled.makeWH(uv_width_scaled, uv_height_scaled);
+ // The target raster dimensions get passed through:
+ // |target_pixmap|.info() -> |pixmap|->info() -> |info| -> |y_info_scaled|
+ const gfx::Size target_raster_size(y_info_scaled.width(),
+ y_info_scaled.height());
+ gfx::Size unscaled_u_size(unscaled_pixmap_u.width(),
+ unscaled_pixmap_u.height());
+ gfx::Size unscaled_v_size(unscaled_pixmap_v.width(),
+ unscaled_pixmap_v.height());
+ gfx::Size scaled_u_size;
+ gfx::Size scaled_v_size;
+ ComputeMippedUVPlaneSizes(target_raster_size, unscaled_u_size,
+ unscaled_v_size, draw_image, &scaled_u_size,
+ &scaled_v_size);
+ const SkImageInfo u_info_scaled =
+ y_info_scaled.makeWH(scaled_u_size.width(), scaled_u_size.height());
+ const SkImageInfo v_info_scaled =
+ y_info_scaled.makeWH(scaled_v_size.width(), scaled_v_size.height());
const size_t y_plane_bytes = y_info_scaled.computeMinByteSize();
- const size_t u_plane_bytes = uv_info_scaled.computeMinByteSize();
+ const size_t u_plane_bytes = u_info_scaled.computeMinByteSize();
DCHECK(!SkImageInfo::ByteSizeOverflowed(y_plane_bytes));
DCHECK(!SkImageInfo::ByteSizeOverflowed(u_plane_bytes));
pixmap_y->reset(y_info_scaled, data_ptr, y_info_scaled.minRowBytes());
- pixmap_u->reset(uv_info_scaled, data_ptr + y_plane_bytes,
- uv_info_scaled.minRowBytes());
- pixmap_v->reset(uv_info_scaled, data_ptr + y_plane_bytes + u_plane_bytes,
- uv_info_scaled.minRowBytes());
+ pixmap_u->reset(u_info_scaled, data_ptr + y_plane_bytes,
+ u_info_scaled.minRowBytes());
+ pixmap_v->reset(v_info_scaled, data_ptr + y_plane_bytes + u_plane_bytes,
+ v_info_scaled.minRowBytes());
const bool all_planes_scaled_successfully =
unscaled_pixmap_y.scalePixels(*pixmap_y, filter_quality) &&
@@ -520,10 +581,12 @@ class ImageUploadTaskImpl : public TileTask {
ImageUploadTaskImpl(GpuImageDecodeCache* cache,
const DrawImage& draw_image,
scoped_refptr<TileTask> decode_dependency,
+ sk_sp<SkData> encoded_data,
const ImageDecodeCache::TracingInfo& tracing_info)
: TileTask(false),
cache_(cache),
image_(draw_image),
+ encoded_data_(std::move(encoded_data)),
tracing_info_(tracing_info) {
DCHECK(!SkipImage(draw_image));
// If an image is already decoded and locked, we will not generate a
@@ -539,7 +602,7 @@ class ImageUploadTaskImpl : public TileTask {
void RunOnWorkerThread() override {
TRACE_EVENT2("cc", "ImageUploadTaskImpl::RunOnWorkerThread", "mode", "gpu",
"source_prepare_tiles_id", tracing_info_.prepare_tiles_id);
- cache_->UploadImageInTask(image_);
+ cache_->UploadImageInTask(image_, std::move(encoded_data_));
}
// Overridden from TileTask:
@@ -553,6 +616,7 @@ class ImageUploadTaskImpl : public TileTask {
private:
GpuImageDecodeCache* cache_;
DrawImage image_;
+ sk_sp<SkData> encoded_data_;
const ImageDecodeCache::TracingInfo tracing_info_;
};
@@ -601,8 +665,11 @@ int GpuImageDecodeCache::ImageDataBase::UsageState() const {
return state;
}
-GpuImageDecodeCache::DecodedImageData::DecodedImageData(bool is_bitmap_backed)
- : is_bitmap_backed_(is_bitmap_backed) {}
+GpuImageDecodeCache::DecodedImageData::DecodedImageData(
+ bool is_bitmap_backed,
+ bool do_hardware_accelerated_decode)
+ : is_bitmap_backed_(is_bitmap_backed),
+ do_hardware_accelerated_decode_(do_hardware_accelerated_decode) {}
GpuImageDecodeCache::DecodedImageData::~DecodedImageData() {
ResetData();
}
@@ -684,6 +751,14 @@ void GpuImageDecodeCache::DecodedImageData::ResetData() {
}
void GpuImageDecodeCache::DecodedImageData::ReportUsageStats() const {
+ if (do_hardware_accelerated_decode_) {
+ // When doing hardware decode acceleration, we don't want to record usage
+ // stats for the decode data. The reason is that the decode is done in the
+ // GPU process and the decoded result stays there. On the renderer side, we
+ // don't use or lock the decoded data, so reporting this status would
+ // incorrectly distort the software decoding statistics.
+ return;
+ }
UMA_HISTOGRAM_ENUMERATION("Renderer4.GpuImageDecodeState",
static_cast<ImageUsageState>(UsageState()),
IMAGE_USAGE_STATE_COUNT);
@@ -786,6 +861,7 @@ GpuImageDecodeCache::ImageData::ImageData(
int upload_scale_mip_level,
bool needs_mips,
bool is_bitmap_backed,
+ bool do_hardware_accelerated_decode,
bool is_yuv_format)
: paint_image_id(paint_image_id),
mode(mode),
@@ -796,7 +872,7 @@ GpuImageDecodeCache::ImageData::ImageData(
needs_mips(needs_mips),
is_bitmap_backed(is_bitmap_backed),
is_yuv(is_yuv_format),
- decode(is_bitmap_backed) {}
+ decode(is_bitmap_backed, do_hardware_accelerated_decode) {}
GpuImageDecodeCache::ImageData::~ImageData() {
// We should never delete ImageData while it is in use or before it has been
@@ -923,9 +999,17 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
scoped_refptr<ImageData> new_data;
+ sk_sp<SkData> encoded_data;
if (!image_data) {
- // We need an ImageData, create one now.
- new_data = CreateImageData(draw_image);
+ // We need an ImageData, create one now. Note that hardware decode
+ // acceleration is allowed only in the DecodeTaskType::kPartOfUploadTask
+ // case. This prevents the img.decode() and checkerboard images paths from
+ // going through hardware decode acceleration.
+ new_data = CreateImageData(
+ draw_image,
+ task_type ==
+ DecodeTaskType::kPartOfUploadTask /* allow_hardware_decode */,
+ &encoded_data);
image_data = new_data.get();
} else if (image_data->decode.decode_failure) {
// We have already tried and failed to decode this image, so just return.
@@ -976,7 +1060,7 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
task = base::MakeRefCounted<ImageUploadTaskImpl>(
this, draw_image,
GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type),
- tracing_info);
+ std::move(encoded_data), tracing_info);
image_data->upload.task = task;
} else {
task = GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type);
@@ -1015,9 +1099,11 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
base::AutoLock lock(lock_);
const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
+ sk_sp<SkData> encoded_data;
if (!image_data) {
// We didn't find the image, create a new entry.
- auto data = CreateImageData(draw_image);
+ auto data = CreateImageData(draw_image, true /* allow_hardware_decode */,
+ &encoded_data);
image_data = data.get();
AddToPersistentCache(draw_image, std::move(data));
}
@@ -1032,7 +1118,7 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
// We may or may not need to decode and upload the image we've found, the
// following functions early-out to if we already decoded.
DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster);
- UploadImageIfNecessary(draw_image, image_data);
+ UploadImageIfNecessary(draw_image, image_data, std::move(encoded_data));
// Unref the image decode, but not the image. The image ref will be released
// in DrawWithImageFinished.
UnrefImageDecode(draw_image, cache_key);
@@ -1299,7 +1385,8 @@ void GpuImageDecodeCache::DecodeImageInTask(const DrawImage& draw_image,
DecodeImageIfNecessary(draw_image, image_data, task_type);
}
-void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) {
+void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image,
+ sk_sp<SkData> encoded_data) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::UploadImage");
base::Optional<viz::RasterContextProvider::ScopedRasterContextLock>
@@ -1319,7 +1406,7 @@ void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) {
if (image_data->is_bitmap_backed)
DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster);
- UploadImageIfNecessary(draw_image, image_data);
+ UploadImageIfNecessary(draw_image, image_data, std::move(encoded_data));
}
void GpuImageDecodeCache::OnImageDecodeTaskCompleted(
@@ -1365,8 +1452,7 @@ void GpuImageDecodeCache::OnImageUploadTaskCompleted(
UnrefImageInternal(draw_image, cache_key);
}
-// Checks if an existing image decode exists. If not, returns a task to produce
-// the requested decode.
+// Checks if an image decode needs a decode task and returns it.
scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef(
const DrawImage& draw_image,
const TracingInfo& tracing_info,
@@ -1384,6 +1470,9 @@ scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef(
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
DCHECK(image_data);
+ if (image_data->decode.do_hardware_accelerated_decode())
+ return nullptr;
+
// No decode is necessary for bitmap backed images.
if (image_data->decode.is_locked() || image_data->is_bitmap_backed) {
// We should never be creating a decode task for a not budgeted image.
@@ -1625,6 +1714,28 @@ bool GpuImageDecodeCache::ExceedsPreferredCount() const {
return persistent_cache_.size() > items_limit;
}
+void GpuImageDecodeCache::InsertTransferCacheEntry(
+ const ClientImageTransferCacheEntry& image_entry,
+ ImageData* image_data) {
+ DCHECK(image_data);
+ uint32_t size = image_entry.SerializedSize();
+ void* data = context_->ContextSupport()->MapTransferCacheEntry(size);
+ if (data) {
+ bool succeeded = image_entry.Serialize(
+ base::make_span(reinterpret_cast<uint8_t*>(data), size));
+ DCHECK(succeeded);
+ context_->ContextSupport()->UnmapAndCreateTransferCacheEntry(
+ image_entry.UnsafeType(), image_entry.Id());
+ image_data->upload.SetTransferCacheId(image_entry.Id());
+ } else {
+ // Transfer cache entry can fail due to a lost gpu context or failure
+ // to allocate shared memory. Handle this gracefully. Mark this
+ // image as "decode failed" so that we do not try to handle it again.
+ // If this was a lost context, we'll recreate this image decode cache.
+ image_data->decode.decode_failure = true;
+ }
+}
+
void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
ImageData* image_data,
TaskType task_type) {
@@ -1632,6 +1743,11 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
DCHECK_GT(image_data->decode.ref_count, 0u);
+ if (image_data->decode.do_hardware_accelerated_decode()) {
+ // We get here in the case of an at-raster decode.
+ return;
+ }
+
if (image_data->decode.decode_failure) {
// We have already tried and failed to decode this image. Don't try again.
return;
@@ -1661,7 +1777,6 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
}
TRACE_EVENT0("cc,benchmark", "GpuImageDecodeCache::DecodeImage");
- RecordImageMipLevelUMA(image_data->upload_scale_mip_level);
image_data->decode.ResetData();
std::unique_ptr<base::DiscardableMemory> backing_memory;
@@ -1747,7 +1862,8 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
}
void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
- ImageData* image_data) {
+ ImageData* image_data,
+ sk_sp<SkData> encoded_data) {
CheckContextLockAcquiredIfNecessary();
lock_.AssertAcquired();
@@ -1776,11 +1892,15 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
return;
TRACE_EVENT0("cc", "GpuImageDecodeCache::UploadImage");
- DCHECK(image_data->decode.is_locked());
+ if (!image_data->decode.do_hardware_accelerated_decode()) {
+ // These are not needed for accelerated decodes because there was no decode
+ // task.
+ DCHECK(image_data->decode.is_locked());
+ image_data->decode.mark_used();
+ }
DCHECK_GT(image_data->decode.ref_count, 0u);
DCHECK_GT(image_data->upload.ref_count, 0u);
- image_data->decode.mark_used();
sk_sp<SkColorSpace> color_space =
SupportsColorSpaceConversion() &&
draw_image.target_color_space().IsValid()
@@ -1799,27 +1919,76 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
if (image_data->mode == DecodedDataMode::kTransferCache) {
DCHECK(use_transfer_cache_);
- SkPixmap pixmap;
- if (!image_data->decode.image()->peekPixels(&pixmap))
+ if (image_data->decode.do_hardware_accelerated_decode()) {
+ // The assumption is that scaling is not currently supported for
+ // hardware-accelerated decodes.
+ DCHECK_EQ(0, image_data->upload_scale_mip_level);
+ const gfx::Size output_size(draw_image.paint_image().width(),
+ draw_image.paint_image().height());
+ // Try to get the encoded data if we don't have it already: this can
+ // happen, e.g., if we create an upload task using a pre-existing
+ // ImageData. In that case, we previously decided to do hardware decode
+ // acceleration but we didn't cache the encoded data.
+ if (!encoded_data) {
+ encoded_data = draw_image.paint_image().GetSkImage()->refEncodedData();
+ DCHECK(encoded_data);
+ }
+ const uint32_t transfer_cache_id =
+ ClientImageTransferCacheEntry::GetNextId();
+ const gpu::SyncToken decode_sync_token =
+ context_->RasterInterface()->ScheduleImageDecode(
+ base::make_span<const uint8_t>(encoded_data->bytes(),
+ encoded_data->size()),
+ output_size, transfer_cache_id,
+ color_space ? gfx::ColorSpace(*color_space) : gfx::ColorSpace(),
+ image_data->needs_mips);
+
+ if (!decode_sync_token.HasData()) {
+ image_data->decode.decode_failure = true;
+ return;
+ }
+
+ image_data->upload.SetTransferCacheId(transfer_cache_id);
+
+ // Note that we wait for the decode sync token here for two reasons:
+ //
+ // 1) To make sure that raster work that depends on the image decode
+ // happens after the decode completes.
+ //
+ // 2) To protect the transfer cache entry from being unlocked on the
+ // service side before the decode is completed.
+ context_->RasterInterface()->WaitSyncTokenCHROMIUM(
+ decode_sync_token.GetConstData());
+
return;
+ }
- ClientImageTransferCacheEntry image_entry(&pixmap, color_space.get(),
- image_data->needs_mips);
- uint32_t size = image_entry.SerializedSize();
- void* data = context_->ContextSupport()->MapTransferCacheEntry(size);
- if (data) {
- bool succeeded = image_entry.Serialize(
- base::make_span(reinterpret_cast<uint8_t*>(data), size));
- DCHECK(succeeded);
- context_->ContextSupport()->UnmapAndCreateTransferCacheEntry(
- image_entry.UnsafeType(), image_entry.Id());
- image_data->upload.SetTransferCacheId(image_entry.Id());
+ // Non-hardware-accelerated path.
+ if (image_data->is_yuv) {
+ SkPixmap y_pixmap;
+ SkPixmap u_pixmap;
+ SkPixmap v_pixmap;
+ if (!image_data->decode.y_image()->peekPixels(&y_pixmap) ||
+ !image_data->decode.u_image()->peekPixels(&u_pixmap) ||
+ !image_data->decode.v_image()->peekPixels(&v_pixmap)) {
+ return;
+ }
+ // WebP documentation says to use Rec 601 for converting to RGB.
+ // TODO(crbug.com/915707): Change QueryYUVA8 to set the colorspace based
+ // on image type.
+ SkYUVColorSpace yuva_color_space =
+ SkYUVColorSpace::kRec601_SkYUVColorSpace;
+ ClientImageTransferCacheEntry image_entry(
+ &y_pixmap, &u_pixmap, &v_pixmap, decoded_target_colorspace.get(),
+ yuva_color_space, image_data->needs_mips);
+ InsertTransferCacheEntry(image_entry, image_data);
} else {
- // Transfer cache entry can fail due to a lost gpu context or failure
- // to allocate shared memory. Handle this gracefully. Mark this
- // image as "decode failed" so that we do not try to handle it again.
- // If this was a lost context, we'll recreate this image decode cache.
- image_data->decode.decode_failure = true;
+ SkPixmap pixmap;
+ if (!image_data->decode.image()->peekPixels(&pixmap))
+ return;
+ ClientImageTransferCacheEntry image_entry(&pixmap, color_space.get(),
+ image_data->needs_mips);
+ InsertTransferCacheEntry(image_entry, image_data);
}
return;
@@ -1968,7 +2137,9 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
}
scoped_refptr<GpuImageDecodeCache::ImageData>
-GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) {
+GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image,
+ bool allow_hardware_decode,
+ sk_sp<SkData>* encoded_data) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::CreateImageData");
lock_.AssertAcquired();
@@ -1977,12 +2148,13 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) {
bool needs_mips = ShouldGenerateMips(draw_image, upload_scale_mip_level);
SkImageInfo image_info =
CreateImageInfoForDrawImage(draw_image, upload_scale_mip_level);
-
+ const bool image_larger_than_max_texture =
+ image_info.width() > max_texture_size_ ||
+ image_info.height() > max_texture_size_;
DecodedDataMode mode;
if (use_transfer_cache_) {
mode = DecodedDataMode::kTransferCache;
- } else if (image_info.width() > max_texture_size_ ||
- image_info.height() > max_texture_size_) {
+ } else if (image_larger_than_max_texture) {
// Image too large to upload. Try to use SW fallback.
mode = DecodedDataMode::kCpu;
} else {
@@ -2009,18 +2181,84 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) {
const bool is_bitmap_backed = !draw_image.paint_image().IsLazyGenerated() &&
upload_scale_mip_level == 0 &&
!cache_color_conversion_on_cpu;
- const bool is_yuv =
- draw_image.paint_image().IsYuv() && mode == DecodedDataMode::kGpu;
+
+ // Figure out if we will do hardware accelerated decoding. The criteria is as
+ // follows:
+ //
+ // - The kVaapiJpegImageDecodeAcceleration feature is enabled.
+ // - The caller allows hardware decodes.
+ // - We are using the transfer cache (OOP-R).
+ // - The image does not require downscaling for uploading (see TODO below).
+ // - All the encoded data was received prior to any decoding work. Otherwise,
+ // it means that the software decoder has already started decoding the
+ // image, so we just let it finish.
+ // - The image's color space is sRGB. This is because we don't currently
+ // support detecting embedded color profiles.
+ // - The image is supported according to the profiles advertised by the GPU
+ // service. Checking this involves obtaining the contiguous encoded data
+ // which may require a copy if the data is not already contiguous. Because
+ // of this, we return a pointer to the contiguous data (as |encoded_data|)
+ // so that we can re-use it later (when requesting the image decode).
+ //
+ // TODO(crbug.com/953363): ideally, we can make the hardware decoder support
+ // decision without requiring contiguous data.
+ //
+ // TODO(crbug.com/953367): currently, we don't support scaling with hardware
+ // decode acceleration. Note that it's still okay for the image to be
+ // downscaled by Skia using the GPU.
+ //
+ // TODO(crbug.com/981208): |data_size| needs to be set to the size of the
+ // decoded data, but for accelerated decodes we won't know until the driver
+ // gives us the result in the GPU process. Figure out what to do.
+ bool do_hardware_accelerated_decode = false;
+ if (base::FeatureList::IsEnabled(
+ features::kVaapiJpegImageDecodeAcceleration) &&
+ allow_hardware_decode && mode == DecodedDataMode::kTransferCache &&
+ upload_scale_mip_level == 0 &&
+ draw_image.paint_image().IsEligibleForAcceleratedDecoding() &&
+ draw_image.paint_image().color_space() &&
+ draw_image.paint_image().color_space()->isSRGB()) {
+ sk_sp<SkData> tmp_encoded_data =
+ draw_image.paint_image().GetSkImage()
+ ? draw_image.paint_image().GetSkImage()->refEncodedData()
+ : nullptr;
+ if (tmp_encoded_data &&
+ context_->ContextSupport()->CanDecodeWithHardwareAcceleration(
+ base::make_span<const uint8_t>(tmp_encoded_data->bytes(),
+ tmp_encoded_data->size()))) {
+ do_hardware_accelerated_decode = true;
+ DCHECK(encoded_data);
+ *encoded_data = std::move(tmp_encoded_data);
+ }
+ }
+
+ // If draw_image.paint_image().IsEligibleForAcceleratedDecoding() returns
+ // true, the image should not be backed by a bitmap.
+ DCHECK(!do_hardware_accelerated_decode || !is_bitmap_backed);
+
+ SkYUVASizeInfo target_yuva_size_info;
+ const bool is_yuv = !do_hardware_accelerated_decode &&
+ draw_image.paint_image().IsYuv(&target_yuva_size_info) &&
+ mode != DecodedDataMode::kCpu &&
+ !image_larger_than_max_texture;
// TODO(crbug.com/910276): Change after alpha support.
- // TODO(crbug.com/915972): Remove YUV420 assumption.
if (is_yuv) {
- // We can't use |temp_yuva_size_info| because it doesn't know about
- // any scaling based on mip levels that |image_info| does incorporate.
size_t y_size_bytes = image_info.width() * image_info.height();
- size_t u_size_bytes =
- ((image_info.width() + 1) / 2) * ((image_info.height() + 1) / 2);
- size_t v_size_bytes = u_size_bytes;
+ const gfx::Size target_raster_size(image_info.width(), image_info.height());
+ gfx::Size unscaled_u_size(
+ target_yuva_size_info.fSizes[SkYUVAIndex::kU_Index].width(),
+ target_yuva_size_info.fSizes[SkYUVAIndex::kU_Index].height());
+ gfx::Size unscaled_v_size(
+ target_yuva_size_info.fSizes[SkYUVAIndex::kV_Index].width(),
+ target_yuva_size_info.fSizes[SkYUVAIndex::kV_Index].height());
+ gfx::Size scaled_u_size;
+ gfx::Size scaled_v_size;
+ ComputeMippedUVPlaneSizes(target_raster_size, unscaled_u_size,
+ unscaled_v_size, draw_image, &scaled_u_size,
+ &scaled_v_size);
+ size_t u_size_bytes = base::checked_cast<size_t>(scaled_u_size.GetArea());
+ size_t v_size_bytes = base::checked_cast<size_t>(scaled_v_size.GetArea());
data_size = y_size_bytes + u_size_bytes + v_size_bytes;
}
@@ -2028,7 +2266,7 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) {
draw_image.paint_image().stable_id(), mode, data_size,
draw_image.target_color_space(),
CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level,
- needs_mips, is_bitmap_backed, is_yuv));
+ needs_mips, is_bitmap_backed, do_hardware_accelerated_decode, is_yuv));
}
void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) {
@@ -2350,7 +2588,8 @@ bool GpuImageDecodeCache::IsCompatible(const ImageData* image_data,
size_t GpuImageDecodeCache::GetDrawImageSizeForTesting(const DrawImage& image) {
base::AutoLock lock(lock_);
- scoped_refptr<ImageData> data = CreateImageData(image);
+ scoped_refptr<ImageData> data = CreateImageData(
+ image, false /* allow_hardware_decode */, nullptr /* encoded_data */);
return data->size;
}
@@ -2394,6 +2633,9 @@ sk_sp<SkImage> GpuImageDecodeCache::GetSWImageDecodeForTesting(
return image_data->decode.ImageForTesting();
}
+// Used for in-process-raster YUV decoding tests, where we often need the
+// SkImages for each underlying plane because asserting or requesting fields for
+// the YUV SkImage may flatten it to RGB or not be possible to request.
sk_sp<SkImage> GpuImageDecodeCache::GetUploadedPlaneForTesting(
const DrawImage& draw_image,
size_t index) {
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h
index 81ca6286703..638a77f2388 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.h
+++ b/chromium/cc/tiles/gpu_image_decode_cache.h
@@ -16,7 +16,9 @@
#include "base/synchronization/lock.h"
#include "base/trace_event/memory_dump_provider.h"
#include "cc/cc_export.h"
+#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/tiles/image_decode_cache.h"
+#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkYUVAIndex.h"
#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
@@ -36,9 +38,9 @@ namespace cc {
// Generally, when an image is required for raster, GpuImageDecodeCache
// creates two tasks, one to decode the image, and one to upload the image to
// the GPU. These tasks are completed before the raster task which depends on
-// the image. We need to seperate decode and upload tasks, as decode can occur
+// the image. We need to separate decode and upload tasks, as decode can occur
// simultaneously on multiple threads, while upload requires the GL context
-// lock must happen on our non-concurrent raster thread.
+// lock so it must happen on our non-concurrent raster thread.
//
// Decoded and Uploaded image data share a single cache entry. Depending on how
// far we've progressed, this cache entry may contain CPU-side decoded data,
@@ -97,6 +99,35 @@ namespace cc {
// keeps an ImageData alive while it is present in either the
// |persistent_cache_| or |in_use_cache_|.
//
+// HARDWARE ACCELERATED DECODES:
+//
+// In Chrome OS, we have the ability to use specialized hardware to decode
+// certain images. Because this requires interacting with drivers, it must be
+// done in the GPU process. Therefore, we follow a different path than the usual
+// decode -> upload tasks:
+// 1) We decide whether to do hardware decode acceleration for an image before
+// we create the decode/upload tasks. Under the hood, this involves parsing
+// the image and checking if it's supported by the hardware decoder
+// according to information advertised by the GPU process. Also, we only
+// allow hardware decoding in OOP-R mode.
+// 2) If we do decide to do hardware decoding, we don't create a decode task.
+// Instead, we create only an upload task and store enough state to
+// indicate that the image will go through this hardware accelerated path.
+// The reason that we use the upload task is that we need to hold the
+// context lock in order to schedule the image decode.
+// 3) When the upload task runs, we send a request to the GPU process to start
+// the image decode. This is an IPC message that does not require us to
+// wait for the response. Instead, we get a sync token that is signalled
+// when the decode completes. We insert a wait for this sync token right
+// after sending the decode request.
+//
+// We also handle the more unusual case where images are decoded at raster time.
+// The process is similar: we skip the software decode and then request the
+// hardware decode in the same way as step (3) above.
+//
+// Note that the decoded data never makes it back to the renderer. It stays in
+// the GPU process. The sync token ensures that any raster work that needs the
+// image happens after the decode completes.
class CC_EXPORT GpuImageDecodeCache
: public ImageDecodeCache,
public base::trace_event::MemoryDumpProvider {
@@ -144,7 +175,7 @@ class CC_EXPORT GpuImageDecodeCache
// Called by Decode / Upload tasks.
void DecodeImageInTask(const DrawImage& image, TaskType task_type);
- void UploadImageInTask(const DrawImage& image);
+ void UploadImageInTask(const DrawImage& image, sk_sp<SkData> encoded_data);
// Called by Decode / Upload tasks when tasks are finished.
void OnImageDecodeTaskCompleted(const DrawImage& image,
@@ -216,7 +247,8 @@ class CC_EXPORT GpuImageDecodeCache
// Stores the CPU-side decoded bits of an image and supporting fields.
struct DecodedImageData : public ImageDataBase {
- explicit DecodedImageData(bool is_bitmap_backed);
+ explicit DecodedImageData(bool is_bitmap_backed,
+ bool do_hardware_accelerated_decode);
~DecodedImageData();
bool Lock();
@@ -255,6 +287,10 @@ class CC_EXPORT GpuImageDecodeCache
bool is_yuv() const { return image_yuv_planes_.has_value(); }
+ bool do_hardware_accelerated_decode() const {
+ return do_hardware_accelerated_decode_;
+ }
+
// Test-only functions.
sk_sp<SkImage> ImageForTesting() const { return image_; }
@@ -278,6 +314,12 @@ class CC_EXPORT GpuImageDecodeCache
std::unique_ptr<base::DiscardableMemory> data_;
sk_sp<SkImage> image_; // RGBX (or null in YUV decode path)
base::Optional<YUVSkImages> image_yuv_planes_;
+
+ // |do_hardware_accelerated_decode_| keeps track of images that should go
+ // through hardware decode acceleration. Currently, this path is intended
+ // only for Chrome OS and only for some JPEG images (see
+ // https://crbug.com/868400).
+ bool do_hardware_accelerated_decode_;
};
// Stores the GPU-side image and supporting fields.
@@ -447,6 +489,7 @@ class CC_EXPORT GpuImageDecodeCache
int upload_scale_mip_level,
bool needs_mips,
bool is_bitmap_backed,
+ bool do_hardware_accelerated_decode,
bool is_yuv_format);
bool IsGpuOrTransferCache() const;
@@ -543,6 +586,9 @@ class CC_EXPORT GpuImageDecodeCache
bool CanFitInWorkingSet(size_t size) const;
bool ExceedsPreferredCount() const;
+ void InsertTransferCacheEntry(
+ const ClientImageTransferCacheEntry& image_entry,
+ ImageData* image_data);
void DecodeImageIfNecessary(const DrawImage& draw_image,
ImageData* image_data,
TaskType task_type);
@@ -557,7 +603,9 @@ class CC_EXPORT GpuImageDecodeCache
sk_sp<SkColorSpace> decoded_color_space) const;
scoped_refptr<GpuImageDecodeCache::ImageData> CreateImageData(
- const DrawImage& image);
+ const DrawImage& image,
+ bool allow_hardware_decode,
+ sk_sp<SkData>* encoded_data);
void WillAddCacheEntry(const DrawImage& draw_image);
SkImageInfo CreateImageInfoForDrawImage(const DrawImage& draw_image,
int upload_scale_mip_level) const;
@@ -591,7 +639,8 @@ class CC_EXPORT GpuImageDecodeCache
// Requires that the |context_| lock be held when calling.
void UploadImageIfNecessary(const DrawImage& draw_image,
- ImageData* image_data);
+ ImageData* image_data,
+ sk_sp<SkData> encoded_data);
// Flush pending operations on context_->GrContext() for each element of
// |yuv_images| and then clear the vector.
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
index a3b7e86666e..70807864351 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
@@ -8,8 +8,8 @@
#include "cc/paint/draw_image.h"
#include "cc/paint/paint_image_builder.h"
#include "cc/raster/tile_task.h"
-#include "cc/test/test_in_process_context_provider.h"
#include "cc/tiles/gpu_image_decode_cache.h"
+#include "components/viz/test/test_in_process_context_provider.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -45,9 +45,10 @@ class GpuImageDecodeCachePerfTest
: timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval),
- context_provider_(base::MakeRefCounted<TestInProcessContextProvider>(
- UseTransferCache(),
- false /* support_locking */)),
+ context_provider_(
+ base::MakeRefCounted<viz::TestInProcessContextProvider>(
+ UseTransferCache(),
+ false /* support_locking */)),
cache_(context_provider_.get(),
UseTransferCache(),
kRGBA_8888_SkColorType,
@@ -87,7 +88,7 @@ class GpuImageDecodeCachePerfTest
}
base::LapTimer timer_;
- scoped_refptr<TestInProcessContextProvider> context_provider_;
+ scoped_refptr<viz::TestInProcessContextProvider> context_provider_;
GpuImageDecodeCache cache_;
};
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
index 77f3210c518..c30c1b1c101 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -6,6 +6,7 @@
#include <memory>
+#include "base/test/scoped_feature_list.h"
#include "cc/paint/draw_image.h"
#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/paint/paint_image_builder.h"
@@ -15,12 +16,20 @@
#include "cc/test/transfer_cache_test_helper.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gles2_interface.h"
+#include "gpu/command_buffer/client/raster_implementation_gles.h"
+#include "gpu/command_buffer/common/command_buffer_id.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/config/gpu_finch_features.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkImageGenerator.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
+using testing::_;
+using testing::StrictMock;
+
namespace cc {
namespace {
@@ -101,13 +110,15 @@ class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface,
public:
explicit FakeGPUImageDecodeTestGLES2Interface(
FakeDiscardableManager* discardable_manager,
- TransferCacheTestHelper* transfer_cache_helper)
+ TransferCacheTestHelper* transfer_cache_helper,
+ bool advertise_accelerated_decoding)
: extension_string_(
"GL_EXT_texture_format_BGRA8888 GL_OES_rgb8_rgba8 "
"GL_OES_texture_npot GL_EXT_texture_rg "
"GL_OES_texture_half_float GL_OES_texture_half_float_linear"),
discardable_manager_(discardable_manager),
- transfer_cache_helper_(transfer_cache_helper) {}
+ transfer_cache_helper_(transfer_cache_helper),
+ advertise_accelerated_decoding_(advertise_accelerated_decoding) {}
~FakeGPUImageDecodeTestGLES2Interface() override {
// All textures / framebuffers / renderbuffers should be cleaned up.
@@ -161,6 +172,11 @@ class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface,
transfer_cache_helper_->DeleteEntryDirect(MakeEntryKey(type, id));
}
+ bool CanDecodeWithHardwareAcceleration(
+ base::span<const uint8_t> encoded_data) const override {
+ return advertise_accelerated_decoding_;
+ }
+
std::pair<TransferCacheEntryType, uint32_t> MakeEntryKey(uint32_t type,
uint32_t id) {
DCHECK_LE(type, static_cast<uint32_t>(TransferCacheEntryType::kLast));
@@ -213,39 +229,78 @@ class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface,
const std::string extension_string_;
FakeDiscardableManager* discardable_manager_;
TransferCacheTestHelper* transfer_cache_helper_;
+ bool advertise_accelerated_decoding_ = false;
size_t mapped_entry_size_ = 0;
std::unique_ptr<uint8_t[]> mapped_entry_;
};
+class MockRasterImplementation : public gpu::raster::RasterImplementationGLES {
+ public:
+ explicit MockRasterImplementation(gpu::gles2::GLES2Interface* gl)
+ : RasterImplementationGLES(gl) {}
+ ~MockRasterImplementation() override = default;
+
+ gpu::SyncToken ScheduleImageDecode(base::span<const uint8_t> encoded_data,
+ const gfx::Size& output_size,
+ uint32_t transfer_cache_entry_id,
+ const gfx::ColorSpace& target_color_space,
+ bool needs_mips) override {
+ DoScheduleImageDecode(output_size, transfer_cache_entry_id,
+ target_color_space, needs_mips);
+ if (!next_accelerated_decode_fails_) {
+ return gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(1u),
+ next_release_count_++);
+ }
+ return gpu::SyncToken();
+ }
+
+ void SetAcceleratedDecodingFailed() { next_accelerated_decode_fails_ = true; }
+
+ MOCK_METHOD4(DoScheduleImageDecode,
+ void(const gfx::Size& /* output_size */,
+ uint32_t /* transfer_cache_entry_id */,
+ const gfx::ColorSpace& /* target_color_space */,
+ bool /* needs_mips */));
+
+ private:
+ bool next_accelerated_decode_fails_ = false;
+ uint64_t next_release_count_ = 1u;
+};
+
class GPUImageDecodeTestMockContextProvider : public viz::TestContextProvider {
public:
static scoped_refptr<GPUImageDecodeTestMockContextProvider> Create(
FakeDiscardableManager* discardable_manager,
- TransferCacheTestHelper* transfer_cache_helper) {
+ TransferCacheTestHelper* transfer_cache_helper,
+ bool advertise_accelerated_decoding) {
+ auto support = std::make_unique<FakeGPUImageDecodeTestGLES2Interface>(
+ discardable_manager, transfer_cache_helper,
+ advertise_accelerated_decoding);
+ auto gl = std::make_unique<FakeGPUImageDecodeTestGLES2Interface>(
+ discardable_manager, transfer_cache_helper,
+ false /* advertise_accelerated_decoding */);
+ auto raster =
+ std::make_unique<StrictMock<MockRasterImplementation>>(gl.get());
return new GPUImageDecodeTestMockContextProvider(
- std::make_unique<FakeGPUImageDecodeTestGLES2Interface>(
- discardable_manager, transfer_cache_helper),
- std::make_unique<FakeGPUImageDecodeTestGLES2Interface>(
- discardable_manager, transfer_cache_helper));
+ std::move(support), std::move(gl), std::move(raster));
}
private:
~GPUImageDecodeTestMockContextProvider() override = default;
GPUImageDecodeTestMockContextProvider(
std::unique_ptr<viz::TestContextSupport> support,
- std::unique_ptr<viz::TestGLES2Interface> gl)
- : TestContextProvider(std::move(support), std::move(gl), true) {}
+ std::unique_ptr<viz::TestGLES2Interface> gl,
+ std::unique_ptr<gpu::raster::RasterInterface> raster)
+ : TestContextProvider(std::move(support),
+ std::move(gl),
+ std::move(raster),
+ true) {}
};
-SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
+SkMatrix CreateMatrix(const SkSize& scale) {
SkMatrix matrix;
matrix.setScale(scale.width(), scale.height());
-
- if (!is_decomposable) {
- // Perspective is not decomposable, add it.
- matrix[SkMatrix::kMPersp0] = 0.1f;
- }
-
return matrix;
}
@@ -260,13 +315,21 @@ SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
size_t kGpuMemoryLimitBytes = 96 * 1024 * 1024;
class GpuImageDecodeCacheTest
- : public ::testing::TestWithParam<std::tuple<SkColorType,
- bool /* use_transfer_cache */,
- bool /* do_yuv_decode */>> {
+ : public ::testing::TestWithParam<
+ std::tuple<SkColorType,
+ bool /* use_transfer_cache */,
+ bool /* do_yuv_decode */,
+ bool /* advertise_accelerated_decoding */>> {
public:
void SetUp() override {
+ advertise_accelerated_decoding_ = std::get<3>(GetParam());
+ if (advertise_accelerated_decoding_) {
+ feature_list_.InitAndEnableFeature(
+ features::kVaapiJpegImageDecodeAcceleration);
+ }
context_provider_ = GPUImageDecodeTestMockContextProvider::Create(
- &discardable_manager_, &transfer_cache_helper_);
+ &discardable_manager_, &transfer_cache_helper_,
+ advertise_accelerated_decoding_);
discardable_manager_.SetGLES2Interface(
context_provider_->UnboundTestContextGL());
context_provider_->BindToCurrentThread();
@@ -351,6 +414,28 @@ class GpuImageDecodeCacheTest
gfx::ColorSpace::TransferID::LINEAR);
}
+ DrawImage CreateDrawImageInternal(
+ const PaintImage& paint_image,
+ const SkMatrix& matrix = SkMatrix::I(),
+ gfx::ColorSpace* color_space = nullptr,
+ SkFilterQuality filter_quality = kMedium_SkFilterQuality,
+ SkIRect* src_rect = nullptr,
+ size_t frame_index = PaintImage::kDefaultFrameIndex) {
+ SkIRect src_rectangle;
+ gfx::ColorSpace cs;
+ if (!src_rect) {
+ src_rectangle =
+ SkIRect::MakeWH(paint_image.width(), paint_image.height());
+ src_rect = &src_rectangle;
+ }
+ if (!color_space) {
+ cs = DefaultColorSpace();
+ color_space = &cs;
+ }
+ return DrawImage(paint_image, *src_rect, filter_quality, matrix,
+ frame_index, *color_space);
+ }
+
GPUImageDecodeTestMockContextProvider* context_provider() {
return context_provider_.get();
}
@@ -404,14 +489,27 @@ class GpuImageDecodeCacheTest
return static_cast<ServiceImageTransferCacheEntry*>(entry)->image();
}
- void CompareAllPlanesToMippedVersions(GpuImageDecodeCache* cache,
- const DrawImage& draw_image,
- bool should_have_mips) {
+ void CompareAllPlanesToMippedVersions(
+ GpuImageDecodeCache* cache,
+ const DrawImage& draw_image,
+ const base::Optional<uint32_t> transfer_cache_id,
+ bool should_have_mips) {
for (size_t i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
// TODO(crbug.com/910276): Skip alpha plane until supported in cache.
if (i != SkYUVAIndex::kA_Index) {
- auto original_uploaded_plane =
- cache->GetUploadedPlaneForTesting(draw_image, i);
+ sk_sp<SkImage> original_uploaded_plane;
+ if (use_transfer_cache_) {
+ DCHECK(transfer_cache_id.has_value());
+ const uint32_t id = transfer_cache_id.value();
+ auto* image_entry =
+ transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>(
+ id);
+ original_uploaded_plane = image_entry->GetPlaneImage(i);
+ } else {
+ original_uploaded_plane =
+ cache->GetUploadedPlaneForTesting(draw_image, i);
+ }
+
ASSERT_TRUE(original_uploaded_plane);
auto plane_with_mips = original_uploaded_plane->makeTextureImage(
context_provider()->GrContext(), nullptr /* color space */,
@@ -422,35 +520,60 @@ class GpuImageDecodeCacheTest
}
}
+ void VerifyUploadedPlaneSizes(
+ GpuImageDecodeCache* cache,
+ const DrawImage& draw_image,
+ const base::Optional<uint32_t> transfer_cache_id,
+ const SkISize plane_sizes[SkYUVASizeInfo::kMaxCount]) {
+ for (size_t i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
+ // TODO(crbug.com/910276): Skip alpha plane until supported in cache.
+ if (i != SkYUVAIndex::kA_Index) {
+ sk_sp<SkImage> uploaded_plane;
+ if (use_transfer_cache_) {
+ DCHECK(transfer_cache_id.has_value());
+ const uint32_t id = transfer_cache_id.value();
+ auto* image_entry =
+ transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>(
+ id);
+ uploaded_plane = image_entry->GetPlaneImage(i);
+ } else {
+ uploaded_plane = cache->GetUploadedPlaneForTesting(draw_image, i);
+ }
+ ASSERT_TRUE(uploaded_plane);
+ EXPECT_EQ(plane_sizes[i], uploaded_plane->dimensions());
+ }
+ }
+ }
+
protected:
+ base::test::ScopedFeatureList feature_list_;
+
+ // The order of these members is important because |context_provider_| depends
+ // on |discardable_manager_| and |transfer_cache_helper_|.
FakeDiscardableManager discardable_manager_;
- scoped_refptr<GPUImageDecodeTestMockContextProvider> context_provider_;
TransferCacheTestHelper transfer_cache_helper_;
+ scoped_refptr<GPUImageDecodeTestMockContextProvider> context_provider_;
+
bool use_transfer_cache_;
SkColorType color_type_;
bool do_yuv_decode_;
+ bool advertise_accelerated_decoding_;
int max_texture_size_ = 0;
};
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
auto cache = CreateCache();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
- DrawImage another_draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage another_draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
another_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
@@ -466,13 +589,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
auto cache = CreateCache();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -482,10 +600,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
EXPECT_EQ(result.task->dependencies().size(), 1u);
EXPECT_TRUE(result.task->dependencies()[0]);
- DrawImage another_draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage another_draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
another_draw_image, ImageDecodeCache::TracingInfo());
@@ -508,21 +624,15 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) {
auto cache = CreateCache();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- bool is_decomposable = true;
- SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
-
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- kHigh_SkFilterQuality, matrix,
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
+ DrawImage draw_image = CreateDrawImageInternal(image, matrix);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
- DrawImage another_draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()),
- kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
- DefaultColorSpace());
+ DrawImage another_draw_image = CreateDrawImageInternal(
+ image, matrix, nullptr /* color_space */, kLow_SkFilterQuality);
ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
another_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
@@ -537,25 +647,18 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage first_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
PaintImage second_image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage second_draw_image(
- second_image,
- SkIRect::MakeWH(second_image.width(), second_image.height()), quality,
- CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage second_draw_image = CreateDrawImageInternal(
+ second_image, CreateMatrix(SkSize::Make(0.25f, 0.25f)));
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
@@ -573,14 +676,10 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage first_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
@@ -591,20 +690,15 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
cache->UnrefImage(first_draw_image);
- DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage second_draw_image = CreateDrawImageInternal(first_image);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
- DrawImage third_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage third_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
third_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
@@ -619,33 +713,23 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage first_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
- DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage second_draw_image = CreateDrawImageInternal(first_image);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
- DrawImage third_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage third_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
third_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
@@ -663,14 +747,10 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
-
+ SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
- DefaultColorSpace());
+ DrawImage first_draw_image = CreateDrawImageInternal(
+ first_image, matrix, nullptr /* color_space */, kLow_SkFilterQuality);
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
@@ -681,10 +761,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) {
cache->UnrefImage(first_draw_image);
- DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
- DefaultColorSpace());
+ DrawImage second_draw_image = CreateDrawImageInternal(
+ first_image, matrix, nullptr /* color_space */, kMedium_SkFilterQuality);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
@@ -698,14 +776,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -740,14 +813,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -782,14 +850,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -813,14 +876,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -856,14 +914,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -903,14 +956,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -932,14 +980,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) {
TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -962,14 +1005,9 @@ TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -996,14 +1034,9 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) {
TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreateLargePaintImageForSoftwareFallback();
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1030,16 +1063,11 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1066,14 +1094,10 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- kLow_SkFilterQuality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)),
+ nullptr /* color_space */, kLow_SkFilterQuality);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1082,10 +1106,8 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
TestTileTaskRunner::ProcessTask(result.task.get());
- DrawImage larger_draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage larger_draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
ImageDecodeCache::TaskResult larger_result = cache->GetTaskForImageAndRef(
larger_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(larger_result.need_unref);
@@ -1121,13 +1143,10 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkMatrix matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable);
-
+ SkMatrix matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f));
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- kLow_SkFilterQuality, matrix,
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(
+ image, matrix, nullptr /* color_space */, kLow_SkFilterQuality);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1136,10 +1155,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
TestTileTaskRunner::ProcessTask(result.task.get());
- DrawImage higher_quality_draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()),
- kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
- DefaultColorSpace());
+ DrawImage higher_quality_draw_image = CreateDrawImageInternal(image, matrix);
ImageDecodeCache::TaskResult hq_result = cache->GetTaskForImageAndRef(
higher_quality_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(hq_result.need_unref);
@@ -1174,14 +1190,9 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(-0.5f, 0.5f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1212,15 +1223,11 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) {
TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreateLargePaintImageForSoftwareFallback(
gfx::Size(GetLargeImageSize().width(), GetLargeImageSize().height() * 2));
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)),
+ nullptr /* color_space */, kHigh_SkFilterQuality);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1253,17 +1260,11 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) {
TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
const gfx::Size test_image_size = GetNormalImageSize();
-
cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
PaintImage image = CreatePaintImageInternal(test_image_size);
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1297,16 +1298,11 @@ TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) {
TEST_P(GpuImageDecodeCacheTest,
GetDecodedImageForDrawAtRasterDecodeMultipleTimes) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
// Must hold context lock before calling GetDecodedImageForDraw /
// DrawWithImageFinished.
@@ -1335,16 +1331,10 @@ TEST_P(GpuImageDecodeCacheTest,
TEST_P(GpuImageDecodeCacheTest,
GetLargeDecodedImageForDrawAtRasterDecodeMultipleTimes) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
PaintImage image = CreateLargePaintImageForSoftwareFallback();
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
// Must hold context lock before calling GetDecodedImageForDraw /
// DrawWithImageFinished.
@@ -1374,14 +1364,9 @@ TEST_P(GpuImageDecodeCacheTest,
TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.f, 0.f)));
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1400,15 +1385,12 @@ TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image(image,
SkIRect::MakeXYWH(image.width() + 1, image.height() + 1,
image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ kMedium_SkFilterQuality,
+ CreateMatrix(SkSize::Make(1.f, 1.f)),
PaintImage::kDefaultFrameIndex, DefaultColorSpace());
ImageDecodeCache::TaskResult result =
@@ -1428,14 +1410,11 @@ TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(
- image, SkIRect::MakeXYWH(0, 0, image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ SkIRect src_rect = SkIRect::MakeXYWH(0, 0, image.width(), image.height());
+ DrawImage draw_image = CreateDrawImageInternal(
+ image, CreateMatrix(SkSize::Make(1.f, 1.f)), nullptr /* color_space */,
+ kMedium_SkFilterQuality, &src_rect);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1454,14 +1433,9 @@ TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) {
TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
{
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo());
@@ -1515,15 +1489,10 @@ TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
// Create a downscaled image.
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage first_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
@@ -1535,10 +1504,8 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) {
// Create a larger version of |first_image|, this should immediately free the
// memory used by |first_image| for the smaller scale.
- DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage second_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
@@ -1563,15 +1530,10 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) {
TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
// Create a downscaled image.
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage first_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
@@ -1587,10 +1549,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) {
// Create a larger version of |first_image|, this should immediately free the
// memory used by |first_image| for the smaller scale.
- DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage second_draw_image = CreateDrawImageInternal(first_image);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
@@ -1610,14 +1569,11 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) {
TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
auto cache = CreateCache();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- bool is_decomposable = true;
- SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
+ SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
// Create an image with kLow_FilterQuality.
- DrawImage low_draw_image(image,
- SkIRect::MakeWH(image.width(), image.height()),
- kLow_SkFilterQuality, matrix,
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage low_draw_image = CreateDrawImageInternal(
+ image, matrix, nullptr /* color_space */, kLow_SkFilterQuality);
ImageDecodeCache::TaskResult low_result = cache->GetTaskForImageAndRef(
low_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(low_result.need_unref);
@@ -1625,21 +1581,16 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
// Get the same image at kMedium_SkFilterQuality. We can't re-use low, so we
// should get a new task/ref.
- DrawImage medium_draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()),
- kMedium_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
- DefaultColorSpace());
+ DrawImage medium_draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult medium_result = cache->GetTaskForImageAndRef(
medium_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(medium_result.need_unref);
EXPECT_TRUE(medium_result.task.get());
EXPECT_FALSE(low_result.task.get() == medium_result.task.get());
- // Get the same image at kHigh_FilterQuality. We should re-use medium.
- DrawImage high_quality_draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()),
- kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
- DefaultColorSpace());
+ // Get the same image at kHigh_SkFilterQuality. We should re-use medium.
+ DrawImage high_quality_draw_image = CreateDrawImageInternal(
+ image, matrix, nullptr /* color_space */, kHigh_SkFilterQuality);
ImageDecodeCache::TaskResult high_quality_result =
cache->GetTaskForImageAndRef(high_quality_draw_image,
ImageDecodeCache::TracingInfo());
@@ -1660,15 +1611,9 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
// cache entry creation doesn't cause a buffer overflow/crash.
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
// Create an image decode task and cache entry that does not need mips.
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1687,10 +1632,8 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
// Do an at-raster decode of the above image that *does* require mips.
- DrawImage draw_image_mips(
- image, SkIRect::MakeWH(image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image_mips =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f)));
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image_mips));
cache->DrawWithImageFinished(draw_image_mips, decoded_draw_image);
@@ -1698,13 +1641,10 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
auto cache = CreateCache();
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- bool is_decomposable = true;
- SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable);
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- kLow_SkFilterQuality, matrix,
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f));
+ DrawImage draw_image = CreateDrawImageInternal(
+ image, matrix, nullptr /* color_space */, kLow_SkFilterQuality);
ImageDecodeCache::TaskResult result =
cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
@@ -1723,16 +1663,10 @@ TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
SetCachedTexturesLimit(0);
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
// Add an image to the cache-> Due to normal working set, this should produce
// a task and a ref.
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1776,19 +1710,13 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
// Cache will fit one image.
SetCachedTexturesLimit(1);
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
PaintImage image2 = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image2(
- image2, SkIRect::MakeWH(image2.width(), image2.height()), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ image2, SkIRect::MakeWH(image2.width(), image2.height()),
+ kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(1.0f, 1.0f)),
PaintImage::kDefaultFrameIndex, DefaultColorSpace());
// Add an image to the cache and un-ref it.
@@ -1858,15 +1786,9 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
TEST_P(GpuImageDecodeCacheTest, ClearCache) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
for (int i = 0; i < 10; ++i) {
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1888,15 +1810,9 @@ TEST_P(GpuImageDecodeCacheTest, ClearCache) {
TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
// Create an image but keep it reffed so it can't be immediately freed.
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1923,36 +1839,27 @@ TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
gfx::ColorSpace color_space_a = gfx::ColorSpace::CreateSRGB();
gfx::ColorSpace color_space_b = gfx::ColorSpace::CreateXYZD50();
PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
- DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, color_space_a);
+ DrawImage first_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a);
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
- DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, color_space_b);
+ DrawImage second_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_b);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
- DrawImage third_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, color_space_a);
+ DrawImage third_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a);
ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
third_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
@@ -1970,15 +1877,10 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
-
PaintImage image = CreateLargePaintImageForSoftwareFallback();
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, color_space);
+ DrawImage draw_image = CreateDrawImageInternal(
+ image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -1992,7 +1894,6 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) {
TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) {
auto cache = CreateCache();
-
std::vector<FrameMetadata> frames = {
FrameMetadata(true, base::TimeDelta::FromMilliseconds(2)),
FrameMetadata(true, base::TimeDelta::FromMilliseconds(3)),
@@ -2014,12 +1915,10 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) {
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
+ SkFilterQuality quality = kMedium_SkFilterQuality;
DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- 1u, DefaultColorSpace());
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), 1u,
+ DefaultColorSpace());
auto decoded_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
ASSERT_TRUE(decoded_image.image());
@@ -2046,8 +1945,7 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) {
ASSERT_LT(subset_height, test_image_size.height());
DrawImage subset_draw_image(
image, SkIRect::MakeWH(subset_width, subset_height), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u,
- DefaultColorSpace());
+ CreateMatrix(SkSize::Make(1.0f, 1.0f)), 3u, DefaultColorSpace());
decoded_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(subset_draw_image));
ASSERT_TRUE(decoded_image.image());
@@ -2059,15 +1957,10 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) {
TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
// Create a downscaled image.
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage first_draw_image = CreateDrawImageInternal(
+ first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
@@ -2078,10 +1971,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) {
// Create a larger version of |first_image|, this should immediately free
// the memory used by |first_image| for the smaller scale.
- DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage second_draw_image = CreateDrawImageInternal(first_image);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
@@ -2114,15 +2004,10 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) {
TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) {
auto cache = CreateCache();
- bool is_decomposable = true;
- const SkFilterQuality quality = kHigh_SkFilterQuality;
const gfx::Size test_image_size = GetNormalImageSize();
PaintImage image = CreatePaintImageInternal(test_image_size);
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
const size_t bytes_for_test_image =
GetBytesNeededForSingleImage(test_image_size);
@@ -2155,8 +2040,6 @@ TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) {
TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
auto cache = CreateCache();
- bool is_decomposable = true;
- const SkFilterQuality quality = kHigh_SkFilterQuality;
const gfx::Size test_image_size = GetNormalImageSize();
// Allow a single image by count. Use a high byte limit as we want to test the
@@ -2166,10 +2049,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
cache->SetWorkingSetLimitsForTesting(
bytes_for_test_image * 100 /* max_bytes */, 1u /* max_items */);
PaintImage image = CreatePaintImageInternal(test_image_size);
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
// The image counts against our budget.
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
@@ -2179,11 +2059,9 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
EXPECT_TRUE(decoded_draw_image.is_budgeted());
// Try another image, it shouldn't be budgeted and should be at-raster.
- DrawImage second_draw_image(
- CreatePaintImageInternal(GetNormalImageSize()),
- SkIRect::MakeWH(image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ PaintImage second_paint_image =
+ CreatePaintImageInternal(GetNormalImageSize());
+ DrawImage second_draw_image = CreateDrawImageInternal(second_paint_image);
// Should be at raster.
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
@@ -2202,15 +2080,10 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
auto cache = CreateCache();
- bool is_decomposable = true;
- const SkFilterQuality quality = kHigh_SkFilterQuality;
const gfx::Size test_image_size = GetNormalImageSize();
PaintImage image = CreatePaintImageInternal(test_image_size);
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
const size_t bytes_for_test_image =
GetBytesNeededForSingleImage(test_image_size);
@@ -2228,11 +2101,8 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
EXPECT_TRUE(decoded_draw_image.is_budgeted());
// Try another image, it shouldn't be budgeted and should be at-raster.
- DrawImage second_draw_image(
- CreatePaintImageInternal(test_image_size),
- SkIRect::MakeWH(image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ PaintImage test_paint_image = CreatePaintImageInternal(test_image_size);
+ DrawImage second_draw_image = CreateDrawImageInternal(test_paint_image);
// Should be at raster.
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
@@ -2252,15 +2122,11 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
TEST_P(GpuImageDecodeCacheTest,
ColorConversionDuringDecodeForLargeImageNonSRGBColorSpace) {
auto cache = CreateCache();
- bool is_decomposable = true;
- const SkFilterQuality quality = kHigh_SkFilterQuality;
gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
PaintImage image = CreateLargePaintImageForSoftwareFallback();
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, color_space);
+ DrawImage draw_image = CreateDrawImageInternal(
+ image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -2307,15 +2173,11 @@ TEST_P(GpuImageDecodeCacheTest,
TEST_P(GpuImageDecodeCacheTest,
ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) {
auto cache = CreateCache();
- bool is_decomposable = true;
- const SkFilterQuality quality = kHigh_SkFilterQuality;
gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65();
PaintImage image = CreatePaintImageInternal(gfx::Size(11, 12));
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, color_space);
+ DrawImage draw_image = CreateDrawImageInternal(
+ image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -2341,9 +2203,11 @@ TEST_P(GpuImageDecodeCacheTest,
EXPECT_EQ(image.width(), service_image->width());
EXPECT_EQ(image.height(), service_image->height());
- // Color space should be logically equal to the original color space.
- EXPECT_TRUE(SkColorSpace::Equals(service_image->colorSpace(),
- target_color_space.get()));
+ if (!do_yuv_decode_) {
+ // Color space should be logically equal to the original color space.
+ EXPECT_TRUE(SkColorSpace::Equals(service_image->colorSpace(),
+ target_color_space.get()));
+ }
} else {
// Ensure that the HW uploaded image had color space conversion applied.
EXPECT_TRUE(SkColorSpace::Equals(decoded_draw_image.image()->colorSpace(),
@@ -2360,14 +2224,9 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadNoScale) {
return;
}
auto cache = CreateCache();
- bool is_decomposable = true;
- const SkFilterQuality quality = kHigh_SkFilterQuality;
PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
@@ -2385,14 +2244,9 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskHasNoDeps) {
return;
}
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
auto result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -2409,14 +2263,9 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskCancelled) {
return;
}
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
auto result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -2437,14 +2286,10 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) {
const bool should_cache_sw_image =
cache->SupportsColorSpaceConversion() && !use_transfer_cache_;
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
-
PaintImage image = CreateBitmapImageInternal(GetLargeImageSize());
- DrawImage draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, gfx::ColorSpace::CreateDisplayP3D65());
+ gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65();
+ DrawImage draw_image = CreateDrawImageInternal(
+ image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
@@ -2456,9 +2301,8 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) {
auto sw_image = cache->GetSWImageDecodeForTesting(draw_image);
ASSERT_EQ(!!sw_image, should_cache_sw_image);
if (should_cache_sw_image) {
- EXPECT_TRUE(SkColorSpace::Equals(
- sw_image->colorSpace(),
- gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace().get()));
+ EXPECT_TRUE(SkColorSpace::Equals(sw_image->colorSpace(),
+ color_space.ToSkColorSpace().get()));
}
}
@@ -2468,14 +2312,10 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadDownscaled) {
return;
}
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
@@ -2486,8 +2326,6 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadDownscaled) {
TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) {
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
const PaintImage::Id paint_image_id = PaintImage::GetNextId();
@@ -2497,10 +2335,8 @@ TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) {
for (int i = 0; i < 10; ++i) {
PaintImage image = CreatePaintImageInternal(
GetNormalImageSize(), SkColorSpace::MakeSRGB(), paint_image_id);
- DrawImage draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
@@ -2536,8 +2372,6 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScale) {
return;
}
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kMedium_SkFilterQuality;
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
const SkISize full_size = SkISize::Make(100, 100);
@@ -2554,10 +2388,8 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScale) {
.set_paint_image_generator(generator)
.TakePaintImage();
- DrawImage draw_image(
- paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(
+ paint_image, CreateMatrix(SkSize::Make(0.5, 0.5)));
DecodedDrawImage decoded_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
const int expected_width =
@@ -2583,8 +2415,6 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) {
return;
}
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kNone_SkFilterQuality;
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
SkISize full_size = SkISize::Make(100, 100);
@@ -2601,10 +2431,9 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) {
.set_paint_image_generator(generator)
.TakePaintImage();
- DrawImage draw_image(
- paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
- quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(paint_image, CreateMatrix(SkSize::Make(0.5, 0.5)),
+ nullptr /* color_space */, kNone_SkFilterQuality);
DecodedDrawImage decoded_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
ASSERT_TRUE(decoded_image.image());
@@ -2627,12 +2456,10 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) {
SkSize scale, gfx::ColorSpace color_space,
bool should_have_mips) {
auto cache = CreateCache();
- bool is_decomposable = true;
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
- DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
- filter_quality, CreateMatrix(scale, is_decomposable),
- PaintImage::kDefaultFrameIndex, color_space);
+ DrawImage draw_image = CreateDrawImageInternal(
+ image, CreateMatrix(scale), &color_space, filter_quality);
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -2644,23 +2471,23 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) {
// Must hold context lock before calling GetDecodedImageForDraw /
// DrawWithImageFinished.
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ // Pull out transfer cache ID from the DecodedDrawImage while it still has
+ // it attached.
+ DecodedDrawImage serialized_decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ const base::Optional<uint32_t> transfer_cache_entry_id =
+ serialized_decoded_draw_image.transfer_cache_entry_id();
DecodedDrawImage decoded_draw_image =
- EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EnsureImageBacked(std::move(serialized_decoded_draw_image));
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
if (do_yuv_decode_) {
- // As of M74, Skia will flatten a YUV SkImage upon calling
- // makeTextureImage. Thus, we must separately request mips for each
- // plane and compare to the original uploaded planes.
- CompareAllPlanesToMippedVersions(cache.get(), draw_image,
- should_have_mips);
- EXPECT_TRUE(
- SkColorSpace::Equals(cache->SupportsColorSpaceConversion()
- ? color_space.ToSkColorSpace().get()
- : nullptr,
- decoded_draw_image.image()->colorSpace()));
-
+ // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
+ // we must separately request mips for each plane and compare to the
+ // original uploaded planes.
+ CompareAllPlanesToMippedVersions(
+ cache.get(), draw_image, transfer_cache_entry_id, should_have_mips);
} else {
sk_sp<SkImage> image_with_mips =
decoded_draw_image.image()->makeTextureImage(
@@ -2688,9 +2515,6 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) {
// Medium filter quality == mips
decode_and_check_mips(kMedium_SkFilterQuality, SkSize::Make(0.6f, 0.6f),
DefaultColorSpace(), true);
- // High filter quality == mips
- decode_and_check_mips(kHigh_SkFilterQuality, SkSize::Make(0.6f, 0.6f),
- DefaultColorSpace(), true);
// Color conversion preserves mips
decode_and_check_mips(kMedium_SkFilterQuality, SkSize::Make(0.6f, 0.6f),
gfx::ColorSpace::CreateXYZD50(), true);
@@ -2698,17 +2522,12 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) {
TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
auto cache = CreateCache();
- bool is_decomposable = true;
- auto filter_quality = kMedium_SkFilterQuality;
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
// Create an image with no scaling. It will not have mips.
{
- DrawImage draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), filter_quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -2720,17 +2539,24 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
// Must hold context lock before calling GetDecodedImageForDraw /
// DrawWithImageFinished.
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ // Pull out transfer cache ID from the DecodedDrawImage while it still has
+ // it attached.
+ DecodedDrawImage serialized_decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ const base::Optional<uint32_t> transfer_cache_entry_id =
+ serialized_decoded_draw_image.transfer_cache_entry_id();
DecodedDrawImage decoded_draw_image =
- EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EnsureImageBacked(std::move(serialized_decoded_draw_image));
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
// No mips should be generated.
if (do_yuv_decode_) {
- // As of M74, Skia will flatten a YUV SkImage upon calling
- // makeTextureImage. Thus, we must separately request mips for each
- // plane and compare to the original uploaded planes.
+ // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
+ // we must separately request mips for each plane and compare to the
+ // original uploaded planes.
CompareAllPlanesToMippedVersions(cache.get(), draw_image,
+ transfer_cache_entry_id,
false /* should_have_mips */);
} else {
sk_sp<SkImage> image_with_mips =
@@ -2750,10 +2576,8 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
// no new task (re-uses the existing image), but mips should have been
// added.
{
- DrawImage draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), filter_quality,
- CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f)));
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -2762,21 +2586,26 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
// Must hold context lock before calling GetDecodedImageForDraw /
// DrawWithImageFinished.
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ // Pull out transfer cache ID from the DecodedDrawImage while it still has
+ // it attached.
+ DecodedDrawImage serialized_decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ const base::Optional<uint32_t> transfer_cache_entry_id =
+ serialized_decoded_draw_image.transfer_cache_entry_id();
DecodedDrawImage decoded_draw_image =
- EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EnsureImageBacked(std::move(serialized_decoded_draw_image));
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
// Mips should be generated
if (do_yuv_decode_) {
+ // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
+ // we must separately request mips for each plane and compare to the
+ // original uploaded planes.
CompareAllPlanesToMippedVersions(cache.get(), draw_image,
+ transfer_cache_entry_id,
true /* should_have_mips */);
- EXPECT_TRUE(
- SkColorSpace::Equals(cache->SupportsColorSpaceConversion()
- ? DefaultColorSpace().ToSkColorSpace().get()
- : nullptr,
- decoded_draw_image.image()->colorSpace()));
} else {
sk_sp<SkImage> image_with_mips =
decoded_draw_image.image()->makeTextureImage(
@@ -2790,9 +2619,6 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
auto cache = CreateCache();
- bool is_decomposable = true;
- auto filter_quality = kMedium_SkFilterQuality;
-
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
struct Decode {
@@ -2803,10 +2629,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
// Create an image with no scaling. It will not have mips.
{
- DrawImage draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), filter_quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -2818,17 +2641,24 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
// Must hold context lock before calling GetDecodedImageForDraw /
// DrawWithImageFinished.
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ // Pull out transfer cache ID from the DecodedDrawImage while it still has
+ // it attached.
+ DecodedDrawImage serialized_decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ const base::Optional<uint32_t> transfer_cache_entry_id =
+ serialized_decoded_draw_image.transfer_cache_entry_id();
DecodedDrawImage decoded_draw_image =
- EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EnsureImageBacked(std::move(serialized_decoded_draw_image));
ASSERT_TRUE(decoded_draw_image.image());
ASSERT_TRUE(decoded_draw_image.image()->isTextureBacked());
// No mips should be generated.
if (do_yuv_decode_) {
- // As of M74, Skia will flatten a YUV SkImage upon calling
- // makeTextureImage. Thus, we must separately request mips for each
- // plane and compare to the original uploaded planes.
+ // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
+ // we must separately request mips for each plane and compare to the
+ // original uploaded planes.
CompareAllPlanesToMippedVersions(cache.get(), draw_image,
+ transfer_cache_entry_id,
false /* should_have_mips */);
} else {
sk_sp<SkImage> image_with_mips =
@@ -2841,10 +2671,8 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
// Second decode with mips.
{
- DrawImage draw_image(
- image, SkIRect::MakeWH(image.width(), image.height()), filter_quality,
- CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f)));
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
@@ -2853,21 +2681,26 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
// Must hold context lock before calling GetDecodedImageForDraw /
// DrawWithImageFinished.
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ // Pull out transfer cache ID from the DecodedDrawImage while it still has
+ // it attached.
+ DecodedDrawImage serialized_decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ const base::Optional<uint32_t> transfer_cache_entry_id =
+ serialized_decoded_draw_image.transfer_cache_entry_id();
DecodedDrawImage decoded_draw_image =
- EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EnsureImageBacked(std::move(serialized_decoded_draw_image));
ASSERT_TRUE(decoded_draw_image.image());
ASSERT_TRUE(decoded_draw_image.image()->isTextureBacked());
// Mips should be generated.
if (do_yuv_decode_) {
+ // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
+ // we must separately request mips for each plane and compare to the
+ // original uploaded planes.
CompareAllPlanesToMippedVersions(cache.get(), draw_image,
+ transfer_cache_entry_id,
true /* should_have_mips */);
- EXPECT_TRUE(
- SkColorSpace::Equals(cache->SupportsColorSpaceConversion()
- ? DefaultColorSpace().ToSkColorSpace().get()
- : nullptr,
- decoded_draw_image.image()->colorSpace()));
} else {
sk_sp<SkImage> image_with_mips =
decoded_draw_image.image()->makeTextureImage(
@@ -2911,21 +2744,139 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
}
}
+TEST_P(GpuImageDecodeCacheTest,
+ OriginalYUVDecodeScaledDrawCorrectlyMipsPlanes) {
+ // This test creates an image that will be YUV decoded and drawn at 80% scale.
+ // Because the final size is between mip levels, we expect the image to be
+ // decoded and uploaded at original size (mip level 0 for all planes) but to
+ // have mips attached since kMedium_SkFilterQuality uses bilinear filtering
+ // between mip levels.
+ if (!do_yuv_decode_) {
+ // The YUV case may choose different mip levels between chroma and luma
+ // planes.
+ return;
+ }
+ auto cache = CreateCache();
+ SkFilterQuality filter_quality = kMedium_SkFilterQuality;
+ SkSize requires_decode_at_original_scale = SkSize::Make(0.8f, 0.8f);
+
+ PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ filter_quality,
+ CreateMatrix(requires_decode_at_original_scale),
+ PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ ImageDecodeCache::TaskResult result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ EXPECT_TRUE(result.task);
+
+ TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result.task.get());
+
+ // Must hold context lock before calling GetDecodedImageForDraw /
+ // DrawWithImageFinished.
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ // Pull out transfer cache ID from the DecodedDrawImage while it still has
+ // it attached.
+ DecodedDrawImage serialized_decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ const base::Optional<uint32_t> transfer_cache_entry_id =
+ serialized_decoded_draw_image.transfer_cache_entry_id();
+ DecodedDrawImage decoded_draw_image =
+ EnsureImageBacked(std::move(serialized_decoded_draw_image));
+ EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+
+ // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, we
+ // must separately request mips for each plane and compare to the original
+ // uploaded planes.
+ CompareAllPlanesToMippedVersions(cache.get(), draw_image,
+ transfer_cache_entry_id,
+ true /* should_have_mips */);
+ SkYUVASizeInfo yuv_size_info = GetYUV420SizeInfo(GetNormalImageSize());
+ VerifyUploadedPlaneSizes(cache.get(), draw_image, transfer_cache_entry_id,
+ yuv_size_info.fSizes);
+
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheTest, ScaledYUVDecodeScaledDrawCorrectlyMipsPlanes) {
+ // This test creates an image that will be YUV decoded and drawn at 45% scale.
+ // Because the final size is between mip levels, we expect the image to be
+ // decoded and uploaded at half its original size (mip level 1 for Y plane but
+ // level 0 for chroma planes) and to have mips attached since
+ // kMedium_SkFilterQuality uses bilinear filtering between mip levels.
+ if (!do_yuv_decode_) {
+ // The YUV case may choose different mip levels between chroma and luma
+ // planes.
+ return;
+ }
+ auto cache = CreateCache();
+ SkFilterQuality filter_quality = kMedium_SkFilterQuality;
+ SkSize less_than_half_scale = SkSize::Make(0.45f, 0.45f);
+
+ gfx::Size image_size = GetNormalImageSize();
+ PaintImage image = CreatePaintImageInternal(image_size);
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ filter_quality, CreateMatrix(less_than_half_scale),
+ PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ ImageDecodeCache::TaskResult result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ EXPECT_TRUE(result.task);
+
+ TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result.task.get());
+
+ // Must hold context lock before calling GetDecodedImageForDraw /
+ // DrawWithImageFinished.
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ // Pull out transfer cache ID from the DecodedDrawImage while it still has
+ // it attached.
+ DecodedDrawImage serialized_decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ const base::Optional<uint32_t> transfer_cache_entry_id =
+ serialized_decoded_draw_image.transfer_cache_entry_id();
+ DecodedDrawImage decoded_draw_image =
+ EnsureImageBacked(std::move(serialized_decoded_draw_image));
+ EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+
+ // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, we
+ // must separately request mips for each plane and compare to the original
+ // uploaded planes.
+ CompareAllPlanesToMippedVersions(cache.get(), draw_image,
+ transfer_cache_entry_id,
+ true /* should_have_mips */);
+
+ // Because we intend to draw this image at 0.45 x 0.45 scale, we will upload
+ // the Y plane at mip level 1 (corresponding to half the original size). The
+ // chroma planes (U and V) should be uploaded at the same size as the Y plane,
+ // corresponding to mip level 0, because the largest dimensions greater than
+ // or equal to target dimensions for them is their original size.
+ SkISize mipped_plane_sizes[SkYUVASizeInfo::kMaxCount];
+ mipped_plane_sizes[SkYUVAIndex::kY_Index] = SkISize::Make(
+ (image_size.width() + 1) / 2, (image_size.height() + 1) / 2);
+ mipped_plane_sizes[SkYUVAIndex::kU_Index] =
+ mipped_plane_sizes[SkYUVAIndex::kY_Index];
+ mipped_plane_sizes[SkYUVAIndex::kV_Index] =
+ mipped_plane_sizes[SkYUVAIndex::kY_Index];
+ VerifyUploadedPlaneSizes(cache.get(), draw_image, transfer_cache_entry_id,
+ mipped_plane_sizes);
+
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+}
+
TEST_P(GpuImageDecodeCacheTest, GetBorderlineLargeDecodedImageForDraw) {
// We will create a texture that's at the maximum size the GPU says it can
// support for uploads.
auto cache = CreateCache();
- bool is_decomposable = true;
- SkFilterQuality quality = kHigh_SkFilterQuality;
PaintImage almost_too_large_image =
CreatePaintImageInternal(gfx::Size(max_texture_size_, max_texture_size_));
- DrawImage draw_image(almost_too_large_image,
- SkIRect::MakeWH(almost_too_large_image.width(),
- almost_too_large_image.height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DrawImage draw_image = CreateDrawImageInternal(almost_too_large_image);
ImageDecodeCache::TaskResult result =
cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -2959,16 +2910,326 @@ bool true_array[] = {true};
INSTANTIATE_TEST_SUITE_P(
GpuImageDecodeCacheTestsInProcessRaster,
GpuImageDecodeCacheTest,
- testing::Combine(testing::ValuesIn(test_color_types),
- testing::ValuesIn(false_array) /* use_transfer_cache */,
- testing::Bool() /* do_yuv_decode */));
+ testing::Combine(
+ testing::ValuesIn(test_color_types),
+ testing::ValuesIn(false_array) /* use_transfer_cache */,
+ testing::Bool() /* do_yuv_decode */,
+ testing::ValuesIn(false_array) /* advertise_accelerated_decoding */));
INSTANTIATE_TEST_SUITE_P(
GpuImageDecodeCacheTestsOOPR,
GpuImageDecodeCacheTest,
- testing::Combine(testing::ValuesIn(test_color_types),
- testing::ValuesIn(true_array) /* use_transfer_cache */,
- testing::ValuesIn(false_array) /* do_yuv_decode */));
+ testing::Combine(
+ testing::ValuesIn(test_color_types),
+ testing::ValuesIn(true_array) /* use_transfer_cache */,
+ testing::Bool() /* do_yuv_decode */,
+ testing::ValuesIn(false_array) /* advertise_accelerated_decoding */));
+
+class GpuImageDecodeCacheWithAcceleratedDecodesTest
+ : public GpuImageDecodeCacheTest {
+ public:
+ PaintImage CreatePaintImageForDecodeAcceleration(
+ const gfx::Size& size,
+ sk_sp<SkColorSpace> color_space = nullptr,
+ bool is_eligible_for_accelerated_decoding = true) {
+ SkImageInfo info =
+ SkImageInfo::Make(size.width(), size.height(), color_type_,
+ kPremul_SkAlphaType, color_space);
+ sk_sp<FakePaintImageGenerator> generator;
+ if (do_yuv_decode_) {
+ generator =
+ sk_make_sp<FakePaintImageGenerator>(info, GetYUV420SizeInfo(size));
+ } else {
+ generator = sk_make_sp<FakePaintImageGenerator>(info);
+ }
+ if (is_eligible_for_accelerated_decoding)
+ generator->SetEligibleForAcceleratedDecoding();
+ PaintImage image = PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .TakePaintImage();
+ return image;
+ }
+
+ StrictMock<MockRasterImplementation>* raster_implementation() const {
+ return static_cast<StrictMock<MockRasterImplementation>*>(
+ context_provider_->RasterInterface());
+ }
+};
+
+TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
+ RequestAcceleratedDecodeSuccessfully) {
+ auto cache = CreateCache();
+ const gfx::Size image_size = GetNormalImageSize();
+ const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
+ const gfx::ColorSpace target_color_space(*image_color_space);
+ ASSERT_TRUE(target_color_space.IsValid());
+ const PaintImage image =
+ CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+ const SkFilterQuality quality = kHigh_SkFilterQuality;
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
+ PaintImage::kDefaultFrameIndex, target_color_space);
+ ImageDecodeCache::TaskResult result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ ASSERT_TRUE(result.task);
+
+ // Accelerated decodes should not produce decode tasks.
+ ASSERT_TRUE(result.task->dependencies().empty());
+ EXPECT_CALL(*raster_implementation(),
+ DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _))
+ .Times(1);
+ TestTileTaskRunner::ProcessTask(result.task.get());
+
+ // Must hold context lock before calling GetDecodedImageForDraw /
+ // DrawWithImageFinished.
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ const DecodedDrawImage decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value());
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
+ RequestAcceleratedDecodeSuccessfullyWithColorSpaceConversion) {
+ auto cache = CreateCache();
+ const gfx::Size image_size = GetNormalImageSize();
+ const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
+ const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50();
+ ASSERT_TRUE(target_color_space.IsValid());
+ const PaintImage image =
+ CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+ const SkFilterQuality quality = kHigh_SkFilterQuality;
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
+ PaintImage::kDefaultFrameIndex, target_color_space);
+ ImageDecodeCache::TaskResult result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ ASSERT_TRUE(result.task);
+
+ // Accelerated decodes should not produce decode tasks.
+ ASSERT_TRUE(result.task->dependencies().empty());
+ EXPECT_CALL(*raster_implementation(),
+ DoScheduleImageDecode(image_size, _,
+ cache->SupportsColorSpaceConversion()
+ ? target_color_space
+ : gfx::ColorSpace(),
+ _))
+ .Times(1);
+ TestTileTaskRunner::ProcessTask(result.task.get());
+
+ // Must hold context lock before calling GetDecodedImageForDraw /
+ // DrawWithImageFinished.
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ const DecodedDrawImage decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value());
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
+ AcceleratedDecodeRequestFails) {
+ auto cache = CreateCache();
+ const gfx::Size image_size = GetNormalImageSize();
+ const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
+ const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50();
+ ASSERT_TRUE(target_color_space.IsValid());
+ const PaintImage image =
+ CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+ const SkFilterQuality quality = kHigh_SkFilterQuality;
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
+ PaintImage::kDefaultFrameIndex, target_color_space);
+ ImageDecodeCache::TaskResult result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ ASSERT_TRUE(result.task);
+
+ // Accelerated decodes should not produce decode tasks.
+ ASSERT_TRUE(result.task->dependencies().empty());
+ raster_implementation()->SetAcceleratedDecodingFailed();
+ EXPECT_CALL(*raster_implementation(),
+ DoScheduleImageDecode(image_size, _,
+ cache->SupportsColorSpaceConversion()
+ ? target_color_space
+ : gfx::ColorSpace(),
+ _))
+ .Times(1);
+ TestTileTaskRunner::ProcessTask(result.task.get());
+
+ // Must hold context lock before calling GetDecodedImageForDraw /
+ // DrawWithImageFinished.
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ const DecodedDrawImage decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ EXPECT_FALSE(decoded_draw_image.transfer_cache_entry_id().has_value());
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
+ CannotRequestAcceleratedDecodeBecauseOfStandAloneDecode) {
+ auto cache = CreateCache();
+ const gfx::Size image_size = GetNormalImageSize();
+ const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
+ const gfx::ColorSpace target_color_space(*image_color_space);
+ ASSERT_TRUE(target_color_space.IsValid());
+ const PaintImage image =
+ CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+ const SkFilterQuality quality = kHigh_SkFilterQuality;
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)),
+ PaintImage::kDefaultFrameIndex, target_color_space);
+ ImageDecodeCache::TaskResult result =
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
+ EXPECT_TRUE(result.need_unref);
+ ASSERT_TRUE(result.task);
+
+ // A non-accelerated standalone decode should produce only a decode task.
+ ASSERT_TRUE(result.task->dependencies().empty());
+ TestTileTaskRunner::ProcessTask(result.task.get());
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
+ CannotRequestAcceleratedDecodeBecauseOfNonZeroUploadMipLevel) {
+ auto cache = CreateCache();
+ const gfx::Size image_size = GetNormalImageSize();
+ const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
+ const gfx::ColorSpace target_color_space(*image_color_space);
+ ASSERT_TRUE(target_color_space.IsValid());
+ const PaintImage image =
+ CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+ const SkFilterQuality quality = kHigh_SkFilterQuality;
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f)),
+ PaintImage::kDefaultFrameIndex, target_color_space);
+ ImageDecodeCache::TaskResult result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ ASSERT_TRUE(result.task);
+
+ // A non-accelerated normal decode should produce a decode dependency.
+ ASSERT_EQ(result.task->dependencies().size(), 1u);
+ ASSERT_TRUE(result.task->dependencies()[0]);
+ TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result.task.get());
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
+ CannotRequestAcceleratedDecodeBecauseOfIneligiblePaintImage) {
+ auto cache = CreateCache();
+ const gfx::Size image_size = GetNormalImageSize();
+ const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
+ const gfx::ColorSpace target_color_space(*image_color_space);
+ ASSERT_TRUE(target_color_space.IsValid());
+ const PaintImage image = CreatePaintImageForDecodeAcceleration(
+ image_size, image_color_space,
+ false /* is_eligible_for_accelerated_decoding */);
+ const SkFilterQuality quality = kHigh_SkFilterQuality;
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)),
+ PaintImage::kDefaultFrameIndex, target_color_space);
+ ImageDecodeCache::TaskResult result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ ASSERT_TRUE(result.task);
+
+ // A non-accelerated normal decode should produce a decode dependency.
+ ASSERT_EQ(result.task->dependencies().size(), 1u);
+ ASSERT_TRUE(result.task->dependencies()[0]);
+ TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result.task.get());
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
+ CannotRequestAcceleratedDecodeBecauseOfNonSRGBColorSpace) {
+ auto cache = CreateCache();
+ const gfx::Size image_size = GetNormalImageSize();
+ const sk_sp<SkColorSpace> image_color_space =
+ SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB);
+ const gfx::ColorSpace target_color_space(*image_color_space);
+ ASSERT_TRUE(target_color_space.IsValid());
+ const PaintImage image =
+ CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+ const SkFilterQuality quality = kHigh_SkFilterQuality;
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)),
+ PaintImage::kDefaultFrameIndex, target_color_space);
+ ImageDecodeCache::TaskResult result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ ASSERT_TRUE(result.task);
+
+ // A non-accelerated normal decode should produce a decode dependency.
+ ASSERT_EQ(result.task->dependencies().size(), 1u);
+ ASSERT_TRUE(result.task->dependencies()[0]);
+ TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result.task.get());
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
+ RequestAcceleratedDecodeSuccessfullyAfterCancellation) {
+ auto cache = CreateCache();
+ const gfx::Size image_size = GetNormalImageSize();
+ const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
+ const gfx::ColorSpace target_color_space(*image_color_space);
+ ASSERT_TRUE(target_color_space.IsValid());
+ const PaintImage image =
+ CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+ const SkFilterQuality quality = kHigh_SkFilterQuality;
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
+ PaintImage::kDefaultFrameIndex, target_color_space);
+ ImageDecodeCache::TaskResult result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ ASSERT_TRUE(result.task);
+
+ // Accelerated decodes should not produce decode tasks.
+ ASSERT_TRUE(result.task->dependencies().empty());
+
+ // Cancel the upload.
+ TestTileTaskRunner::CancelTask(result.task.get());
+ TestTileTaskRunner::CompleteTask(result.task.get());
+
+ // Get the image again - we should have an upload task.
+ ImageDecodeCache::TaskResult another_result =
+ cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(another_result.need_unref);
+ ASSERT_TRUE(another_result.task);
+ EXPECT_EQ(another_result.task->dependencies().size(), 0u);
+ EXPECT_CALL(*raster_implementation(),
+ DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _))
+ .Times(1);
+ TestTileTaskRunner::ProcessTask(another_result.task.get());
+
+ // Must hold context lock before calling GetDecodedImageForDraw /
+ // DrawWithImageFinished.
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ const DecodedDrawImage decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+ EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value());
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+ cache->UnrefImage(draw_image);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ GpuImageDecodeCacheTestsOOPR,
+ GpuImageDecodeCacheWithAcceleratedDecodesTest,
+ testing::Combine(
+ testing::ValuesIn(test_color_types),
+ testing::ValuesIn(true_array) /* use_transfer_cache */,
+ testing::Bool() /* do_yuv_decode */,
+ testing::ValuesIn(true_array) /* advertise_accelerated_decoding */));
#undef EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE
#undef EXPECT_FALSE_IF_NOT_USING_TRANSFER_CACHE
diff --git a/chromium/cc/tiles/image_controller.cc b/chromium/cc/tiles/image_controller.cc
index 919be166e5f..9f600462eb8 100644
--- a/chromium/cc/tiles/image_controller.cc
+++ b/chromium/cc/tiles/image_controller.cc
@@ -21,8 +21,7 @@ ImageController::ImageController(
base::SequencedTaskRunner* origin_task_runner,
scoped_refptr<base::SequencedTaskRunner> worker_task_runner)
: worker_task_runner_(std::move(worker_task_runner)),
- origin_task_runner_(origin_task_runner),
- weak_ptr_factory_(this) {
+ origin_task_runner_(origin_task_runner) {
weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
}
@@ -129,11 +128,6 @@ void ImageController::StopWorkerTasks() {
image_decode_queue_.clear();
}
-void ImageController::SetPaintWorkletLayerPainter(
- std::unique_ptr<PaintWorkletLayerPainter> painter) {
- paint_worklet_image_cache_.SetPaintWorkletLayerPainter(std::move(painter));
-}
-
void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) {
DCHECK(!cache_ || !cache);
@@ -152,27 +146,7 @@ void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) {
}
}
-void ImageController::ConvertPaintWorkletImagesToTask(
- std::vector<DrawImage>* sync_decoded_images,
- std::vector<scoped_refptr<TileTask>>* tasks) {
- for (auto it = sync_decoded_images->begin();
- it != sync_decoded_images->end();) {
- if (!it->paint_image().IsPaintWorklet()) {
- ++it;
- continue;
- }
- scoped_refptr<TileTask> result =
- paint_worklet_image_cache_.GetTaskForPaintWorkletImage(*it);
- if (result)
- tasks->push_back(std::move(result));
- // Remove it so that there is no need to check whether an image is
- // PaintWorklet generated or not in TileManager's
- // work_to_schedule->extra_prepaint_images.insert.
- it = sync_decoded_images->erase(it);
- }
-}
-
-void ImageController::ConvertDataImagesToTasks(
+void ImageController::ConvertImagesToTasks(
std::vector<DrawImage>* sync_decoded_images,
std::vector<scoped_refptr<TileTask>>* tasks,
bool* has_at_raster_images,
@@ -181,10 +155,10 @@ void ImageController::ConvertDataImagesToTasks(
*has_at_raster_images = false;
for (auto it = sync_decoded_images->begin();
it != sync_decoded_images->end();) {
- if (it->paint_image().IsPaintWorklet()) {
- ++it;
- continue;
- }
+ // PaintWorklet images should not be included in this set; they have already
+ // been painted before raster and so do not need raster-time work.
+ DCHECK(!it->paint_image().IsPaintWorklet());
+
ImageDecodeCache::TaskResult result =
cache_->GetTaskForImageAndRef(*it, tracing_info);
*has_at_raster_images |= result.IsAtRaster();
@@ -212,8 +186,8 @@ std::vector<scoped_refptr<TileTask>> ImageController::SetPredecodeImages(
const ImageDecodeCache::TracingInfo& tracing_info) {
std::vector<scoped_refptr<TileTask>> new_tasks;
bool has_at_raster_images = false;
- ConvertDataImagesToTasks(&images, &new_tasks, &has_at_raster_images,
- tracing_info);
+ ConvertImagesToTasks(&images, &new_tasks, &has_at_raster_images,
+ tracing_info);
UnrefImages(predecode_locked_images_);
predecode_locked_images_ = std::move(images);
return new_tasks;
diff --git a/chromium/cc/tiles/image_controller.h b/chromium/cc/tiles/image_controller.h
index 2533b6e50f2..1ec832d13c1 100644
--- a/chromium/cc/tiles/image_controller.h
+++ b/chromium/cc/tiles/image_controller.h
@@ -19,7 +19,6 @@
#include "cc/paint/draw_image.h"
#include "cc/raster/tile_task.h"
#include "cc/tiles/image_decode_cache.h"
-#include "cc/tiles/paint_worklet_image_cache.h"
namespace cc {
@@ -39,32 +38,17 @@ class CC_EXPORT ImageController {
ImageController& operator=(const ImageController&) = delete;
void SetImageDecodeCache(ImageDecodeCache* cache);
- void SetPaintWorkletLayerPainter(
- std::unique_ptr<PaintWorkletLayerPainter> painter);
- // The name "Data images" are the images that are not generated by
- // PaintWorklet.
- // Build tile tasks for synchronously decoded images that are not generated by
- // PaintWorklet.
+ // Build tile tasks for synchronously decoded images.
// |sync_decoded_images| is the input. These are the images from a particular
// tile, retrieved by the DiscardableImageMap. Images can be removed from the
// vector under certain conditions.
// |tasks| is an output, which are the built tile tasks.
// |has_at_raster_images| is an output parameter.
// |tracing_info| is used in tracing or UMA only.
- void ConvertDataImagesToTasks(
- std::vector<DrawImage>* sync_decoded_images,
- std::vector<scoped_refptr<TileTask>>* tasks,
- bool* has_at_raster_images,
- const ImageDecodeCache::TracingInfo& tracing_info);
- // TODO(crbug.com/915566): bundle all tasks into a big TaskBag.
- // Build tile tasks for images that are generated by PaintWorklet.
- // |sync_decoded_images| is the input, which are the images from a particular
- // tile, retrieved by DiscardableImageMap. Images are removed from the vector
- // once the tile task is built.
- // |tasks| is an output, which are the built tile tasks.
- void ConvertPaintWorkletImagesToTask(
- std::vector<DrawImage>* sync_decoded_images,
- std::vector<scoped_refptr<TileTask>>* tasks);
+ void ConvertImagesToTasks(std::vector<DrawImage>* sync_decoded_images,
+ std::vector<scoped_refptr<TileTask>>* tasks,
+ bool* has_at_raster_images,
+ const ImageDecodeCache::TracingInfo& tracing_info);
void UnrefImages(const std::vector<DrawImage>& images);
void ReduceMemoryUsage();
std::vector<scoped_refptr<TileTask>> SetPredecodeImages(
@@ -90,9 +74,6 @@ class CC_EXPORT ImageController {
}
ImageDecodeCache* cache() const { return cache_; }
- PaintWorkletImageCache* paint_worklet_image_cache() {
- return &paint_worklet_image_cache_;
- }
protected:
scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
@@ -128,7 +109,6 @@ class CC_EXPORT ImageController {
base::WeakPtr<ImageController> weak_ptr_;
ImageDecodeCache* cache_ = nullptr;
- PaintWorkletImageCache paint_worklet_image_cache_;
std::vector<DrawImage> predecode_locked_images_;
static ImageDecodeRequestId s_next_image_decode_queue_id_;
@@ -151,7 +131,7 @@ class CC_EXPORT ImageController {
// from generating new tasks, this vector should be empty.
std::vector<ImageDecodeRequest> orphaned_decode_requests_;
- base::WeakPtrFactory<ImageController> weak_ptr_factory_;
+ base::WeakPtrFactory<ImageController> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/tiles/image_controller_unittest.cc b/chromium/cc/tiles/image_controller_unittest.cc
index 1c3e0d3b215..17b20018fb2 100644
--- a/chromium/cc/tiles/image_controller_unittest.cc
+++ b/chromium/cc/tiles/image_controller_unittest.cc
@@ -244,9 +244,7 @@ DrawImage CreateBitmapDrawImage(gfx::Size size) {
class ImageControllerTest : public testing::Test {
public:
- ImageControllerTest()
- : task_runner_(base::SequencedTaskRunnerHandle::Get()),
- weak_ptr_factory_(this) {
+ ImageControllerTest() : task_runner_(base::SequencedTaskRunnerHandle::Get()) {
image_ = CreateDiscardableDrawImage(gfx::Size(1, 1));
}
~ImageControllerTest() override = default;
@@ -314,31 +312,9 @@ class ImageControllerTest : public testing::Test {
std::unique_ptr<ImageController> controller_;
DrawImage image_;
- base::WeakPtrFactory<ImageControllerTest> weak_ptr_factory_;
+ base::WeakPtrFactory<ImageControllerTest> weak_ptr_factory_{this};
};
-// Test that GetTasksForImagesAndRef does not generate task for PaintWorklet
-// images.
-TEST_F(ImageControllerTest, GetTasksForImagesAndRefForPaintWorkletImages) {
- std::vector<DrawImage> images(1);
- ImageDecodeCache::TracingInfo tracing_info;
-
- PaintImage paint_image = CreatePaintImage(100, 100);
- DrawImage draw_image(
- paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
- kNone_SkFilterQuality, CreateMatrix(SkSize::Make(1.f, 1.f), true),
- PaintImage::kDefaultFrameIndex);
- images[0] = draw_image;
-
- ASSERT_EQ(1u, images.size());
-
- std::vector<scoped_refptr<TileTask>> tasks;
- bool has_at_raster_images = false;
- controller()->ConvertDataImagesToTasks(&images, &tasks, &has_at_raster_images,
- tracing_info);
- EXPECT_EQ(tasks.size(), 0u);
-}
-
TEST_F(ImageControllerTest, NullControllerUnrefsImages) {
std::vector<DrawImage> images(10);
ImageDecodeCache::TracingInfo tracing_info;
diff --git a/chromium/cc/tiles/image_decode_cache.cc b/chromium/cc/tiles/image_decode_cache.cc
index 7c83ee45a15..9c68e3cc26c 100644
--- a/chromium/cc/tiles/image_decode_cache.cc
+++ b/chromium/cc/tiles/image_decode_cache.cc
@@ -4,7 +4,6 @@
#include "cc/tiles/image_decode_cache.h"
-#include "base/metrics/histogram_macros.h"
#include "cc/raster/tile_task.h"
namespace cc {
@@ -19,11 +18,4 @@ ImageDecodeCache::TaskResult::TaskResult(const TaskResult& result) = default;
ImageDecodeCache::TaskResult::~TaskResult() = default;
-void ImageDecodeCache::RecordImageMipLevelUMA(int mip_level) {
- DCHECK_GE(mip_level, 0);
- DCHECK_LT(mip_level, 32);
- UMA_HISTOGRAM_EXACT_LINEAR("Renderer4.ImageDecodeMipLevel", mip_level + 1,
- 33);
-}
-
} // namespace cc
diff --git a/chromium/cc/tiles/image_decode_cache.h b/chromium/cc/tiles/image_decode_cache.h
index 6d7d339ee28..241f5772b02 100644
--- a/chromium/cc/tiles/image_decode_cache.h
+++ b/chromium/cc/tiles/image_decode_cache.h
@@ -143,9 +143,6 @@ class CC_EXPORT ImageDecodeCache {
// image can directly be used for raster (for instance bitmaps in a software
// draw).
virtual bool UseCacheForDrawImage(const DrawImage& image) const = 0;
-
- protected:
- void RecordImageMipLevelUMA(int mip_level);
};
} // namespace cc
diff --git a/chromium/cc/tiles/paint_worklet_image_cache.cc b/chromium/cc/tiles/paint_worklet_image_cache.cc
deleted file mode 100644
index d0bd702cae7..00000000000
--- a/chromium/cc/tiles/paint_worklet_image_cache.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2018 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/tiles/paint_worklet_image_cache.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "cc/paint/paint_worklet_layer_painter.h"
-
-namespace cc {
-
-class PaintWorkletTaskImpl : public TileTask {
- public:
- PaintWorkletTaskImpl(PaintWorkletImageCache* cache,
- const PaintImage& paint_image)
- : TileTask(true), cache_(cache), paint_image_(paint_image) {}
- PaintWorkletTaskImpl(const PaintWorkletTaskImpl&) = delete;
-
- PaintWorkletTaskImpl& operator=(const PaintWorkletTaskImpl&) = delete;
-
- // Overridden from Task:
- void RunOnWorkerThread() override { cache_->PaintImageInTask(paint_image_); }
-
- // Overridden from TileTask:
- void OnTaskCompleted() override {}
-
- protected:
- ~PaintWorkletTaskImpl() override = default;
-
- private:
- PaintWorkletImageCache* cache_;
- PaintImage paint_image_;
-};
-
-PaintWorkletImageCache::PaintWorkletImageCache() {}
-
-PaintWorkletImageCache::~PaintWorkletImageCache() {
- for (const auto& pair : records_)
- DCHECK_EQ(pair.second.used_ref_count, 0u);
-}
-
-void PaintWorkletImageCache::SetPaintWorkletLayerPainter(
- std::unique_ptr<PaintWorkletLayerPainter> painter) {
- DCHECK(!painter_);
- painter_ = std::move(painter);
-}
-
-scoped_refptr<TileTask> PaintWorkletImageCache::GetTaskForPaintWorkletImage(
- const DrawImage& image) {
- DCHECK(painter_);
- DCHECK(image.paint_image().IsPaintWorklet());
- return base::MakeRefCounted<PaintWorkletTaskImpl>(this, image.paint_image());
-}
-
-// TODO(xidachen): we might need to consider the animated property value and the
-// PaintWorkletInput to decide whether we need to call Paint() function or not.
-void PaintWorkletImageCache::PaintImageInTask(const PaintImage& paint_image) {
- // TODO(crbug.com/939009): When creating a TileTask for a given PaintImage at
- // GetTaskForPaintWorkletImage, we should not create a new TileTask if there
- // is already a TileTask for this PaintImage.
- {
- base::AutoLock hold(records_lock_);
- if (records_.find(paint_image.paint_worklet_input()) != records_.end())
- return;
- }
- // Because the compositor could be waiting on the lock in NotifyPrepareTiles,
- // we unlock here such that the compositor won't be blocked on potentially
- // slow Paint function.
- // TODO(xidachen): ensure that the canvas operations in the PaintRecord
- // matches the PaintGeneratedImage::Draw.
- sk_sp<PaintRecord> record =
- painter_->Paint(paint_image.paint_worklet_input());
- if (!record)
- return;
- {
- base::AutoLock hold(records_lock_);
- // It is possible for two or more threads to both pass through the first
- // lock and arrive here. To avoid ref-count issues caused by potential
- // racing among threads, we use insert such that if an entry already exists
- // for a particular key, the value won't be overridden.
- records_.insert(
- std::make_pair(paint_image.paint_worklet_input(),
- PaintWorkletImageCacheValue(std::move(record), 0)));
- }
-}
-
-std::pair<sk_sp<PaintRecord>, base::OnceCallback<void()>>
-PaintWorkletImageCache::GetPaintRecordAndRef(PaintWorkletInput* input) {
- base::AutoLock hold(records_lock_);
- DCHECK(records_.find(input) != records_.end());
- records_[input].used_ref_count++;
- records_[input].num_of_frames_not_accessed = 0u;
- // The PaintWorkletImageCache object lives as long as the LayerTreeHostImpl,
- // and that ensures that this pointer and the input will be alive when this
- // callback is executed.
- auto callback =
- base::BindOnce(&PaintWorkletImageCache::DecrementCacheRefCount,
- base::Unretained(this), base::Unretained(input));
- return std::make_pair(records_[input].record, std::move(callback));
-}
-
-void PaintWorkletImageCache::SetNumOfFramesToPurgeCacheEntryForTest(
- size_t num) {
- num_of_frames_to_purge_cache_entry_ = num;
-}
-
-void PaintWorkletImageCache::DecrementCacheRefCount(PaintWorkletInput* input) {
- base::AutoLock hold(records_lock_);
- auto it = records_.find(input);
- DCHECK(it != records_.end());
-
- auto& pair = it->second;
- DCHECK_GT(pair.used_ref_count, 0u);
- pair.used_ref_count--;
-}
-
-void PaintWorkletImageCache::NotifyDidPrepareTiles() {
- base::AutoLock hold(records_lock_);
- base::EraseIf(
- records_,
- [this](
- const std::pair<PaintWorkletInput*, PaintWorkletImageCacheValue>& t) {
- return t.second.num_of_frames_not_accessed >=
- num_of_frames_to_purge_cache_entry_ &&
- t.second.used_ref_count == 0;
- });
- for (auto& pair : records_)
- pair.second.num_of_frames_not_accessed++;
-}
-
-PaintWorkletImageCache::PaintWorkletImageCacheValue::
- PaintWorkletImageCacheValue() = default;
-
-PaintWorkletImageCache::PaintWorkletImageCacheValue::
- PaintWorkletImageCacheValue(sk_sp<PaintRecord> record, size_t ref_count)
- : record(std::move(record)), used_ref_count(ref_count) {}
-
-PaintWorkletImageCache::PaintWorkletImageCacheValue::
- PaintWorkletImageCacheValue(const PaintWorkletImageCacheValue& other)
- : record(other.record), used_ref_count(other.used_ref_count) {}
-
-PaintWorkletImageCache::PaintWorkletImageCacheValue::
- ~PaintWorkletImageCacheValue() = default;
-
-} // namespace cc
diff --git a/chromium/cc/tiles/paint_worklet_image_cache.h b/chromium/cc/tiles/paint_worklet_image_cache.h
deleted file mode 100644
index f9b976f357b..00000000000
--- a/chromium/cc/tiles/paint_worklet_image_cache.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef CC_TILES_PAINT_WORKLET_IMAGE_CACHE_H_
-#define CC_TILES_PAINT_WORKLET_IMAGE_CACHE_H_
-
-#include <utility>
-
-#include "base/containers/flat_map.h"
-#include "base/synchronization/lock.h"
-#include "cc/cc_export.h"
-#include "cc/paint/draw_image.h"
-#include "cc/paint/paint_record.h"
-#include "cc/paint/paint_worklet_layer_painter.h"
-#include "cc/raster/tile_task.h"
-#include "cc/tiles/image_decode_cache.h"
-
-namespace cc {
-
-// PaintWorkletImageCache is responsible for generating tasks of executing
-// PaintWorklet JS paint callbacks, and being able to return the generated
-// results when requested.
-class CC_EXPORT PaintWorkletImageCache {
- public:
- struct CC_EXPORT PaintWorkletImageCacheValue {
- PaintWorkletImageCacheValue();
- PaintWorkletImageCacheValue(sk_sp<PaintRecord> record, size_t ref_count);
- PaintWorkletImageCacheValue(const PaintWorkletImageCacheValue&);
- ~PaintWorkletImageCacheValue();
-
- sk_sp<PaintRecord> record;
- size_t used_ref_count;
- // Indicates how many continuous frames that this cache is never accessed or
- // updated. A cache entry should be purged if this number is larger than
- // |num_of_frames_to_purge_cache_entry_|.
- size_t num_of_frames_not_accessed = 0u;
- };
-
- PaintWorkletImageCache();
-
- ~PaintWorkletImageCache();
-
- void SetPaintWorkletLayerPainter(
- std::unique_ptr<PaintWorkletLayerPainter> painter);
-
- scoped_refptr<TileTask> GetTaskForPaintWorkletImage(const DrawImage& image);
-
- void PaintImageInTask(const PaintImage& paint_image);
-
- void NotifyDidPrepareTiles();
-
- // Returns a callback to decrement the ref count for the corresponding entry.
- std::pair<sk_sp<PaintRecord>, base::OnceCallback<void()>>
- GetPaintRecordAndRef(PaintWorkletInput* input);
-
- const base::flat_map<PaintWorkletInput*, PaintWorkletImageCacheValue>&
- GetRecordsForTest() {
- return records_;
- }
-
- void SetNumOfFramesToPurgeCacheEntryForTest(size_t);
-
- private:
- void DecrementCacheRefCount(PaintWorkletInput* input);
-
- // This is a map of paint worklet inputs to a pair of paint record and a
- // reference count. The paint record is the representation of the worklet
- // output based on the input, and the reference count is the number of times
- // that it is used for tile rasterization.
- base::flat_map<PaintWorkletInput*, PaintWorkletImageCacheValue> records_;
-
- // The |records_| can be accessed from compositor and raster worker threads at
- // the same time. To prevent race, we need to lock on it.
- base::Lock records_lock_;
-
- // The PaintWorkletImageCache is owned by ImageController, which has the same
- // life time as the LayerTreeHostImpl, that guarantees that the painter will
- // live as long as the LayerTreeHostImpl.
- std::unique_ptr<PaintWorkletLayerPainter> painter_;
-
- size_t num_of_frames_to_purge_cache_entry_ = 5u;
-};
-
-} // namespace cc
-
-#endif // CC_TILES_PAINT_WORKLET_IMAGE_CACHE_H_
diff --git a/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc b/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc
deleted file mode 100644
index 7af4b9340c6..00000000000
--- a/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2018 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 <memory>
-#include <utility>
-
-#include "cc/tiles/paint_worklet_image_cache.h"
-
-#include "cc/paint/draw_image.h"
-#include "cc/raster/paint_worklet_image_provider.h"
-#include "cc/test/skia_common.h"
-#include "cc/test/test_paint_worklet_input.h"
-#include "cc/test/test_paint_worklet_layer_painter.h"
-#include "cc/test/test_tile_task_runner.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-namespace {
-
-class TestPaintWorkletImageCache : public PaintWorkletImageCache {
- public:
- TestPaintWorkletImageCache() {}
-};
-
-SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
- SkMatrix matrix;
- matrix.setScale(scale.width(), scale.height());
-
- if (!is_decomposable) {
- // Perspective is not decomposable, add it.
- matrix[SkMatrix::kMPersp0] = 0.1f;
- }
-
- return matrix;
-}
-
-PaintImage CreatePaintImage(int width, int height) {
- scoped_refptr<TestPaintWorkletInput> input =
- base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(width, height));
- return CreatePaintWorkletPaintImage(input);
-}
-
-scoped_refptr<TileTask> GetTaskForPaintWorkletImage(
- const PaintImage& paint_image,
- TestPaintWorkletImageCache* cache) {
- DrawImage draw_image(
- paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
- kNone_SkFilterQuality, CreateMatrix(SkSize::Make(1.f, 1.f), true),
- PaintImage::kDefaultFrameIndex);
- return cache->GetTaskForPaintWorkletImage(draw_image);
-}
-
-void TestPaintRecord(const PaintRecord* record) {
- EXPECT_EQ(record->total_op_count(), 1u);
-
- // GetOpAtForTesting check whether the type is the same as DrawImageOp or not.
- // If not, it returns a nullptr.
- auto* paint_op = record->GetOpAtForTesting<DrawImageOp>(0);
- EXPECT_TRUE(paint_op);
-}
-
-TEST(PaintWorkletImageCacheTest, GetTaskForImage) {
- TestPaintWorkletImageCache cache;
- std::unique_ptr<TestPaintWorkletLayerPainter> painter =
- std::make_unique<TestPaintWorkletLayerPainter>();
- cache.SetPaintWorkletLayerPainter(std::move(painter));
- PaintImage paint_image = CreatePaintImage(100, 100);
- scoped_refptr<TileTask> task =
- GetTaskForPaintWorkletImage(paint_image, &cache);
- EXPECT_TRUE(task);
- PaintWorkletImageProvider provider(&cache);
-
- TestTileTaskRunner::ProcessTask(task.get());
-
- {
- ImageProvider::ScopedResult result =
- provider.GetPaintRecordResult(paint_image.paint_worklet_input());
- EXPECT_TRUE(result.paint_record());
- TestPaintRecord(result.paint_record());
-
- base::flat_map<PaintWorkletInput*,
- PaintWorkletImageCache::PaintWorkletImageCacheValue>
- records = cache.GetRecordsForTest();
- // Test the ref count.
- EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u);
- }
- base::flat_map<PaintWorkletInput*,
- PaintWorkletImageCache::PaintWorkletImageCacheValue>
- records = cache.GetRecordsForTest();
- // Test the ref count, which should have been decremented when the result
- // goes out of the scope.
- EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 0u);
-
- {
- ImageProvider::ScopedResult result =
- provider.GetPaintRecordResult(paint_image.paint_worklet_input());
-
- base::flat_map<PaintWorkletInput*,
- PaintWorkletImageCache::PaintWorkletImageCacheValue>
- records = cache.GetRecordsForTest();
- // Test the ref count.
- EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u);
-
- ImageProvider::ScopedResult moved_result = std::move(result);
-
- EXPECT_FALSE(result);
-
- EXPECT_TRUE(moved_result.paint_record());
- TestPaintRecord(moved_result.paint_record());
-
- // Once moved, the ref count from |result| should have been transferred to
- // |moved_result|, so there should be only one un-ref when they both go out
- // of scope.
- EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u);
- }
- EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 0u);
-}
-
-TEST(PaintWorkletImageCacheTest, EntryWithNonZeroRefCountNotPurged) {
- TestPaintWorkletImageCache cache;
- std::unique_ptr<TestPaintWorkletLayerPainter> painter =
- std::make_unique<TestPaintWorkletLayerPainter>();
- cache.SetPaintWorkletLayerPainter(std::move(painter));
- PaintImage paint_image = CreatePaintImage(100, 100);
- scoped_refptr<TileTask> task =
- GetTaskForPaintWorkletImage(paint_image, &cache);
- EXPECT_TRUE(task);
-
- TestTileTaskRunner::ProcessTask(task.get());
-
- PaintWorkletImageProvider provider(&cache);
- ImageProvider::ScopedResult result =
- provider.GetPaintRecordResult(paint_image.paint_worklet_input());
- base::flat_map<PaintWorkletInput*,
- PaintWorkletImageCache::PaintWorkletImageCacheValue>
- records = cache.GetRecordsForTest();
- EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u);
-
- cache.NotifyDidPrepareTiles();
- cache.NotifyDidPrepareTiles();
- cache.NotifyDidPrepareTiles();
-
- records = cache.GetRecordsForTest();
- EXPECT_EQ(records.size(), 1u);
-}
-
-TEST(PaintWorkletImageCacheTest, MultipleRecordsInCache) {
- TestPaintWorkletImageCache cache;
- std::unique_ptr<TestPaintWorkletLayerPainter> painter =
- std::make_unique<TestPaintWorkletLayerPainter>();
- cache.SetPaintWorkletLayerPainter(std::move(painter));
- PaintImage paint_image1 = CreatePaintImage(100, 100);
- scoped_refptr<TileTask> task1 =
- GetTaskForPaintWorkletImage(paint_image1, &cache);
- EXPECT_TRUE(task1);
- PaintImage paint_image2 = CreatePaintImage(200, 200);
- scoped_refptr<TileTask> task2 =
- GetTaskForPaintWorkletImage(paint_image2, &cache);
- EXPECT_TRUE(task2);
-
- TestTileTaskRunner::ProcessTask(task1.get());
- TestTileTaskRunner::ProcessTask(task2.get());
-
- base::flat_map<PaintWorkletInput*,
- PaintWorkletImageCache::PaintWorkletImageCacheValue>
- records = cache.GetRecordsForTest();
- EXPECT_EQ(records.size(), 2u);
-
- cache.SetNumOfFramesToPurgeCacheEntryForTest(2u);
- PaintRecord* record1 =
- records[paint_image1.paint_worklet_input()].record.get();
- EXPECT_TRUE(record1);
- // Test the |num_of_frames_not_accessed| for this cache entry.
- EXPECT_EQ(
- records[paint_image1.paint_worklet_input()].num_of_frames_not_accessed,
- 0u);
- TestPaintRecord(record1);
-
- PaintRecord* record2 =
- records[paint_image2.paint_worklet_input()].record.get();
- EXPECT_TRUE(record2);
- // Test the |num_of_frames_not_accessed| for this cache entry.
- EXPECT_EQ(
- records[paint_image2.paint_worklet_input()].num_of_frames_not_accessed,
- 0u);
- TestPaintRecord(record2);
-
- // NotifyDidPrepareTiles is called by TileManager::PrepareTiles() which is
- // called at each new impl frame. Here we test that a paint record with
- // |num_of_frames_not_accessed| >= 2 is purged from the cache.
- cache.NotifyDidPrepareTiles();
- records = cache.GetRecordsForTest();
- EXPECT_EQ(
- records[paint_image1.paint_worklet_input()].num_of_frames_not_accessed,
- 1u);
- EXPECT_EQ(
- records[paint_image2.paint_worklet_input()].num_of_frames_not_accessed,
- 1u);
-
- std::pair<sk_sp<PaintRecord>, base::OnceCallback<void()>> pair =
- cache.GetPaintRecordAndRef(paint_image1.paint_worklet_input());
- // Run the callback to decrement the ref count.
- std::move(pair.second).Run();
- records = cache.GetRecordsForTest();
- EXPECT_EQ(
- records[paint_image1.paint_worklet_input()].num_of_frames_not_accessed,
- 0u);
-
- cache.NotifyDidPrepareTiles();
- cache.NotifyDidPrepareTiles();
- records = cache.GetRecordsForTest();
- // The cache entry for paint_image2 should have been purged because it was
- // never accessed/updated in the last 2 frames.
- EXPECT_EQ(records.size(), 1u);
- EXPECT_EQ(
- records[paint_image1.paint_worklet_input()].num_of_frames_not_accessed,
- 2u);
-}
-
-// This test ensures that if an entry already exist, then the PaintImageInTask
-// will not replace it with a new entry and reset its ref count.
-TEST(PaintWorkletImageCacheTest, CacheEntryLookup) {
- TestPaintWorkletImageCache cache;
- std::unique_ptr<TestPaintWorkletLayerPainter> painter =
- std::make_unique<TestPaintWorkletLayerPainter>();
- cache.SetPaintWorkletLayerPainter(std::move(painter));
- PaintImage paint_image = CreatePaintImage(100, 100);
- scoped_refptr<TileTask> task =
- GetTaskForPaintWorkletImage(paint_image, &cache);
- EXPECT_TRUE(task);
- PaintWorkletImageProvider provider(&cache);
-
- TestTileTaskRunner::ProcessTask(task.get());
-
- {
- ImageProvider::ScopedResult result =
- provider.GetPaintRecordResult(paint_image.paint_worklet_input());
- EXPECT_TRUE(result.paint_record());
- TestPaintRecord(result.paint_record());
-
- base::flat_map<PaintWorkletInput*,
- PaintWorkletImageCache::PaintWorkletImageCacheValue>
- records = cache.GetRecordsForTest();
- // Test the ref count.
- EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u);
-
- // Create a new task with the same PaintWorkletInput as the previous task.
- // Then ProcessTask will invoke PaintWorkletImageCache::PaintImageInTask,
- // and it should early exit, without replacing the existing PaintRecord and
- // resetting the ref count.
- scoped_refptr<TileTask> task_with_the_same_input =
- GetTaskForPaintWorkletImage(paint_image, &cache);
- EXPECT_TRUE(task);
- TestTileTaskRunner::ProcessTask(task_with_the_same_input.get());
- EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u);
- }
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/tiles/picture_layer_tiling.h b/chromium/cc/tiles/picture_layer_tiling.h
index 4f66d992b35..253fdea09ac 100644
--- a/chromium/cc/tiles/picture_layer_tiling.h
+++ b/chromium/cc/tiles/picture_layer_tiling.h
@@ -17,6 +17,7 @@
#include "cc/base/region.h"
#include "cc/base/tiling_data.h"
#include "cc/cc_export.h"
+#include "cc/paint/paint_worklet_input.h"
#include "cc/tiles/tile.h"
#include "cc/tiles/tile_priority.h"
#include "cc/trees/occlusion.h"
@@ -40,8 +41,7 @@ class CC_EXPORT PictureLayerTilingClient {
// Create a tile at the given content_rect (in the contents scale of the
// tiling) This might return null if the client cannot create such a tile.
virtual std::unique_ptr<Tile> CreateTile(const Tile::CreateInfo& info) = 0;
- virtual gfx::Size CalculateTileSize(
- const gfx::Size& content_bounds) const = 0;
+ virtual gfx::Size CalculateTileSize(const gfx::Size& content_bounds) = 0;
// This invalidation region defines the area (if any, it can by null) that
// tiles can not be shared between pending and active trees.
virtual const Region* GetPendingInvalidation() = 0;
@@ -49,6 +49,7 @@ class CC_EXPORT PictureLayerTilingClient {
const PictureLayerTiling* tiling) const = 0;
virtual bool HasValidTilePriorities() const = 0;
virtual bool RequiresHighResToDraw() const = 0;
+ virtual const PaintWorkletRecordMap& GetPaintWorkletRecords() const = 0;
protected:
virtual ~PictureLayerTilingClient() {}
@@ -135,6 +136,9 @@ class CC_EXPORT PictureLayerTiling {
const scoped_refptr<RasterSource>& raster_source() const {
return raster_source_;
}
+ const PaintWorkletRecordMap& GetPaintWorkletRecords() const {
+ return client_->GetPaintWorkletRecords();
+ }
gfx::Size tiling_size() const { return tiling_data_.tiling_size(); }
gfx::Rect live_tiles_rect() const { return live_tiles_rect_; }
gfx::Size tile_size() const { return tiling_data_.max_texture_size(); }
diff --git a/chromium/cc/tiles/picture_layer_tiling_set.cc b/chromium/cc/tiles/picture_layer_tiling_set.cc
index 38d7ad0e9fa..5a2bcb740a0 100644
--- a/chromium/cc/tiles/picture_layer_tiling_set.cc
+++ b/chromium/cc/tiles/picture_layer_tiling_set.cc
@@ -242,7 +242,7 @@ void PictureLayerTilingSet::CleanUpTilings(
continue;
// Don't remove tilings that are required.
- if (base::ContainsValue(needed_tilings, tiling.get())) {
+ if (base::Contains(needed_tilings, tiling.get())) {
continue;
}
diff --git a/chromium/cc/tiles/prioritized_tile.h b/chromium/cc/tiles/prioritized_tile.h
index a2996602c7f..54538898271 100644
--- a/chromium/cc/tiles/prioritized_tile.h
+++ b/chromium/cc/tiles/prioritized_tile.h
@@ -6,6 +6,7 @@
#define CC_TILES_PRIORITIZED_TILE_H_
#include "cc/cc_export.h"
+#include "cc/paint/paint_worklet_input.h"
#include "cc/raster/raster_source.h"
#include "cc/tiles/picture_layer_tiling.h"
#include "cc/tiles/tile.h"
@@ -32,6 +33,9 @@ class CC_EXPORT PrioritizedTile {
const scoped_refptr<RasterSource>& raster_source() const {
return source_tiling_->raster_source();
}
+ const PaintWorkletRecordMap& GetPaintWorkletRecords() const {
+ return source_tiling_->GetPaintWorkletRecords();
+ }
const TilePriority& priority() const { return priority_; }
bool is_occluded() const { return is_occluded_; }
bool is_process_for_images_only() const {
diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc
index f858a180756..6aa420ce0b5 100644
--- a/chromium/cc/tiles/software_image_decode_cache.cc
+++ b/chromium/cc/tiles/software_image_decode_cache.cc
@@ -76,7 +76,12 @@ class SoftwareImageDecodeTaskImpl : public TileTask {
paint_image_.GetSkImage().get(),
devtools_instrumentation::ScopedImageDecodeTask::kSoftware,
ImageDecodeCache::ToScopedTaskType(tracing_info_.task_type));
- cache_->DecodeImageInTask(image_key_, paint_image_, task_type_);
+ SoftwareImageDecodeCache::TaskProcessingResult result =
+ cache_->DecodeImageInTask(image_key_, paint_image_, task_type_);
+
+ // Do not log timing UMAs if we did not perform a full decode.
+ if (result != SoftwareImageDecodeCache::TaskProcessingResult::kFullDecode)
+ image_decode_task.SuppressMetrics();
}
// Overridden from TileTask:
@@ -300,9 +305,10 @@ void SoftwareImageDecodeCache::UnrefImage(const CacheKey& key) {
}
}
-void SoftwareImageDecodeCache::DecodeImageInTask(const CacheKey& key,
- const PaintImage& paint_image,
- DecodeTaskType task_type) {
+SoftwareImageDecodeCache::TaskProcessingResult
+SoftwareImageDecodeCache::DecodeImageInTask(const CacheKey& key,
+ const PaintImage& paint_image,
+ DecodeTaskType task_type) {
TRACE_EVENT1("cc,benchmark", "SoftwareImageDecodeCache::DecodeImageInTask",
"key", key.ToString());
base::AutoLock lock(lock_);
@@ -316,16 +322,16 @@ void SoftwareImageDecodeCache::DecodeImageInTask(const CacheKey& key,
DCHECK_GT(cache_entry->ref_count, 0);
DCHECK(cache_entry->is_budgeted);
- DecodeImageIfNecessary(key, paint_image, cache_entry);
+ TaskProcessingResult result =
+ DecodeImageIfNecessary(key, paint_image, cache_entry);
DCHECK(cache_entry->decode_failed || cache_entry->is_locked);
- RecordImageMipLevelUMA(
- MipMapUtil::GetLevelForSize(key.src_rect().size(), key.target_size()));
+ return result;
}
-void SoftwareImageDecodeCache::DecodeImageIfNecessary(
- const CacheKey& key,
- const PaintImage& paint_image,
- CacheEntry* entry) {
+SoftwareImageDecodeCache::TaskProcessingResult
+SoftwareImageDecodeCache::DecodeImageIfNecessary(const CacheKey& key,
+ const PaintImage& paint_image,
+ CacheEntry* entry) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"SoftwareImageDecodeCache::DecodeImageIfNecessary", "key",
key.ToString());
@@ -336,18 +342,18 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary(
entry->decode_failed = true;
if (entry->decode_failed)
- return;
+ return TaskProcessingResult::kCancelled;
if (entry->memory) {
if (entry->is_locked)
- return;
+ return TaskProcessingResult::kLockOnly;
bool lock_succeeded = entry->Lock();
// TODO(vmpstr): Deprecate the prepaint split, since it doesn't matter.
RecordLockExistingCachedImageHistogram(TilePriority::NOW, lock_succeeded);
if (lock_succeeded)
- return;
+ return TaskProcessingResult::kLockOnly;
}
std::unique_ptr<CacheEntry> local_cache_entry;
@@ -439,7 +445,7 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary(
if (!local_cache_entry) {
entry->decode_failed = true;
- return;
+ return TaskProcessingResult::kCancelled;
}
// Just in case someone else did this already, just unlock our work.
@@ -457,6 +463,8 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary(
local_cache_entry->MoveImageMemoryTo(entry);
DCHECK(entry->is_locked);
}
+
+ return TaskProcessingResult::kFullDecode;
}
base::Optional<SoftwareImageDecodeCache::CacheKey>
diff --git a/chromium/cc/tiles/software_image_decode_cache.h b/chromium/cc/tiles/software_image_decode_cache.h
index c3b7c03303d..176adeec8ed 100644
--- a/chromium/cc/tiles/software_image_decode_cache.h
+++ b/chromium/cc/tiles/software_image_decode_cache.h
@@ -32,6 +32,10 @@ class CC_EXPORT SoftwareImageDecodeCache
enum class DecodeTaskType { USE_IN_RASTER_TASKS, USE_OUT_OF_RASTER_TASKS };
+ // Identifies whether a decode task performed decode work, or was fulfilled /
+ // failed trivially.
+ enum class TaskProcessingResult { kFullDecode, kLockOnly, kCancelled };
+
SoftwareImageDecodeCache(SkColorType color_type,
size_t locked_memory_limit_bytes,
PaintImage::GeneratorClientId generator_client_id);
@@ -56,9 +60,9 @@ class CC_EXPORT SoftwareImageDecodeCache
// Decode the given image and store it in the cache. This is only called by an
// image decode task from a worker thread.
- void DecodeImageInTask(const CacheKey& key,
- const PaintImage& paint_image,
- DecodeTaskType task_type);
+ TaskProcessingResult DecodeImageInTask(const CacheKey& key,
+ const PaintImage& paint_image,
+ DecodeTaskType task_type);
void OnImageDecodeTaskCompleted(const CacheKey& key,
DecodeTaskType task_type);
@@ -123,9 +127,9 @@ class CC_EXPORT SoftwareImageDecodeCache
CacheEntry* AddCacheEntry(const CacheKey& key);
- void DecodeImageIfNecessary(const CacheKey& key,
- const PaintImage& paint_image,
- CacheEntry* cache_entry);
+ TaskProcessingResult DecodeImageIfNecessary(const CacheKey& key,
+ const PaintImage& paint_image,
+ CacheEntry* cache_entry);
void AddBudgetForImage(const CacheKey& key, CacheEntry* entry);
void RemoveBudgetForImage(const CacheKey& key, CacheEntry* entry);
base::Optional<CacheKey> FindCachedCandidate(const CacheKey& key);
diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.h b/chromium/cc/tiles/software_image_decode_cache_utils.h
index 835d68c8492..3293d8b4cc9 100644
--- a/chromium/cc/tiles/software_image_decode_cache_utils.h
+++ b/chromium/cc/tiles/software_image_decode_cache_utils.h
@@ -50,12 +50,11 @@ class SoftwareImageDecodeCacheUtils {
bool operator==(const CacheKey& other) const {
// The frame_key always has to be the same. However, after that all
// original decodes are the same, so if we can use the original decode,
- // return true. If not, then we have to compare every field. Note we don't
- // compare |nearest_neighbor_| because we would only use kOriginal type in
- // that case (dchecked below), which implies no scale. The returned scale
- // to Skia would respect the nearest neighbor value of the requested
- // image.
- DCHECK(!is_nearest_neighbor_ || type_ == kOriginal);
+ // return true. If not, then we have to compare every field.
+ // |nearest_neighbor_| is not compared below since it is not used for
+ // scaled decodes and does not affect the contents of the cache entry
+ // (just passed to skia for the filtering to be done at raster time).
+ DCHECK(!is_nearest_neighbor_ || type_ != kSubrectAndScale);
return frame_key_ == other.frame_key_ && type_ == other.type_ &&
target_color_space_ == other.target_color_space_ &&
(type_ == kOriginal || (src_rect_ == other.src_rect_ &&
diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc
index 165bb015145..032b487ef5e 100644
--- a/chromium/cc/tiles/tile_manager.cc
+++ b/chromium/cc/tiles/tile_manager.cc
@@ -402,9 +402,7 @@ TileManager::TileManager(
base::Unretained(this))),
has_scheduled_tile_tasks_(false),
prepare_tiles_count_(0u),
- next_tile_id_(0u),
- task_set_finished_weak_ptr_factory_(this),
- ready_to_draw_callback_weak_ptr_factory_(this) {}
+ next_tile_id_(0u) {}
TileManager::~TileManager() {
FinishTasksAndCleanUp();
@@ -550,8 +548,6 @@ bool TileManager::PrepareTiles(
// Schedule tile tasks.
ScheduleTasks(std::move(prioritized_work));
- image_controller_.paint_worklet_image_cache()->NotifyDidPrepareTiles();
-
TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
"state", BasicStateAsValue());
return true;
@@ -779,8 +775,12 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
// If we couldn't fit the tile into our current memory limit, then we're
// done.
if (!memory_usage_is_within_limit) {
- if (tile_is_needed_now)
+ if (tile_is_needed_now) {
+ LOG(ERROR) << "WARNING: tile memory limits exceeded, some content may "
+ "not draw";
+
had_enough_memory_to_schedule_tiles_needed_now = false;
+ }
all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
break;
}
@@ -1190,10 +1190,8 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask(
prepare_tiles_count_, prioritized_tile.priority().priority_bin,
ImageDecodeCache::TaskType::kInRaster);
bool has_at_raster_images = false;
- image_controller_.ConvertDataImagesToTasks(
- &sync_decoded_images, &decode_tasks, &has_at_raster_images, tracing_info);
- image_controller_.ConvertPaintWorkletImagesToTask(&sync_decoded_images,
- &decode_tasks);
+ image_controller_.ConvertImagesToTasks(&sync_decoded_images, &decode_tasks,
+ &has_at_raster_images, tracing_info);
// Notify |decoded_image_tracker_| after |image_controller_| to ensure we've
// taken new refs on the images before releasing the predecode API refs.
decoded_image_tracker_.OnImagesUsedInDraw(sync_decoded_images);
@@ -1246,8 +1244,13 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask(
PlaybackImageProvider image_provider(image_controller_.cache(),
raster_color_space, std::move(settings));
+ // We make a deliberate copy of the PaintWorklet map here, as the
+ // PictureLayerImpl's map could be mutated or destroyed whilst raster from an
+ // earlier snapshot is still ongoing on the raster worker threads.
+ PaintWorkletRecordMap paint_worklet_records =
+ prioritized_tile.GetPaintWorkletRecords();
PaintWorkletImageProvider paint_worklet_image_provider(
- image_controller_.paint_worklet_image_cache());
+ std::move(paint_worklet_records));
DispatchingImageProvider dispatching_image_provider(
std::move(image_provider), std::move(paint_worklet_image_provider));
@@ -1711,11 +1714,6 @@ TileManager::ActivationStateAsValue() {
return std::move(state);
}
-void TileManager::SetPaintWorkletLayerPainter(
- std::unique_ptr<PaintWorkletLayerPainter> painter) {
- image_controller_.SetPaintWorkletLayerPainter(std::move(painter));
-}
-
void TileManager::ActivationStateAsValueInto(
base::trace_event::TracedValue* state) {
state->SetString("tree_priority",
diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h
index 015ce53e837..afa7d42ef37 100644
--- a/chromium/cc/tiles/tile_manager.h
+++ b/chromium/cc/tiles/tile_manager.h
@@ -294,9 +294,6 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
void set_active_url(const GURL& url) { active_url_ = url; }
- void SetPaintWorkletLayerPainter(
- std::unique_ptr<PaintWorkletLayerPainter> painter);
-
protected:
friend class Tile;
// Must be called by tile during destruction.
@@ -473,9 +470,10 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
// different. The |task_set_finished_weak_ptr_factory_| is invalidated any
// time new tasks are scheduled, preventing a race when the callback has
// been scheduled but not yet executed.
- base::WeakPtrFactory<TileManager> task_set_finished_weak_ptr_factory_;
+ base::WeakPtrFactory<TileManager> task_set_finished_weak_ptr_factory_{this};
// The |ready_to_draw_callback_weak_ptr_factory_| is never invalidated.
- base::WeakPtrFactory<TileManager> ready_to_draw_callback_weak_ptr_factory_;
+ base::WeakPtrFactory<TileManager> ready_to_draw_callback_weak_ptr_factory_{
+ this};
};
} // namespace cc
diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc
index 9c6d1e0516b..7b4e57f2e2c 100644
--- a/chromium/cc/tiles/tile_manager_unittest.cc
+++ b/chromium/cc/tiles/tile_manager_unittest.cc
@@ -2583,7 +2583,7 @@ TEST_F(TileManagerReadyToDrawTest, TilePrioritiesUpdated) {
final_num_prepaint++;
} else {
final_num_required++;
- if (base::ContainsValue(prepaint_tiles, tile)) {
+ if (base::Contains(prepaint_tiles, tile)) {
found_one_prepaint_to_required_transition = true;
}
}
diff --git a/chromium/cc/tiles/tile_task_manager.cc b/chromium/cc/tiles/tile_task_manager.cc
index 2bfdd9e88ef..476a7d7a965 100644
--- a/chromium/cc/tiles/tile_task_manager.cc
+++ b/chromium/cc/tiles/tile_task_manager.cc
@@ -5,6 +5,7 @@
#include "cc/tiles/tile_task_manager.h"
#include "base/memory/ptr_util.h"
+#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
namespace cc {
@@ -50,7 +51,10 @@ void TileTaskManagerImpl::Shutdown() {
// Cancel non-scheduled tasks and wait for running tasks to finish.
TaskGraph empty;
task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
- task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
+ {
+ base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
+ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
+ }
}
} // namespace cc
diff --git a/chromium/cc/trees/damage_tracker.cc b/chromium/cc/trees/damage_tracker.cc
index f3ddee21062..743b681dc6a 100644
--- a/chromium/cc/trees/damage_tracker.cc
+++ b/chromium/cc/trees/damage_tracker.cc
@@ -386,7 +386,7 @@ void DamageTracker::AccumulateDamageFromLayer(LayerImpl* layer) {
// If the layer properties haven't changed, then the the target surface is
// only affected by the layer's damaged area, which could be empty.
gfx::Rect damage_rect =
- gfx::UnionRects(layer->update_rect(), layer->damage_rect());
+ gfx::UnionRects(layer->update_rect(), layer->GetDamageRect());
damage_rect.Intersect(gfx::Rect(layer->bounds()));
if (!damage_rect.IsEmpty()) {
@@ -416,7 +416,7 @@ void DamageTracker::AccumulateDamageFromLayer(LayerImpl* layer) {
if (layer_is_new || !layer->update_rect().IsEmpty() ||
layer->LayerPropertyChangedNotFromPropertyTrees() ||
- !layer->damage_rect().IsEmpty() || property_change_on_non_target_node) {
+ !layer->GetDamageRect().IsEmpty() || property_change_on_non_target_node) {
has_damage_from_contributing_content_ |= !damage_for_this_update_.IsEmpty();
}
}
diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc
index fcd75ca4f75..b9046c6644b 100644
--- a/chromium/cc/trees/damage_tracker_unittest.cc
+++ b/chromium/cc/trees/damage_tracker_unittest.cc
@@ -26,6 +26,36 @@
namespace cc {
namespace {
+class TestLayerImpl : public LayerImpl {
+ public:
+ TestLayerImpl(LayerTreeImpl* tree_impl, int id);
+
+ void AddDamageRect(const gfx::Rect& damage_rect);
+
+ // LayerImpl overrides.
+ gfx::Rect GetDamageRect() const override;
+ void ResetChangeTracking() override;
+
+ private:
+ gfx::Rect damage_rect_;
+};
+
+TestLayerImpl::TestLayerImpl(LayerTreeImpl* tree_impl, int id)
+ : LayerImpl(tree_impl, id) {}
+
+void TestLayerImpl::AddDamageRect(const gfx::Rect& damage_rect) {
+ damage_rect_.Union(damage_rect);
+}
+
+gfx::Rect TestLayerImpl::GetDamageRect() const {
+ return damage_rect_;
+}
+
+void TestLayerImpl::ResetChangeTracking() {
+ LayerImpl::ResetChangeTracking();
+ damage_rect_.SetRect(0, 0, 0, 0);
+}
+
void ExecuteCalculateDrawProperties(LayerImpl* root,
float device_scale_factor,
RenderSurfaceList* render_surface_list) {
@@ -71,16 +101,15 @@ class DamageTrackerTest : public testing::Test {
LayerImpl* CreateTestTreeWithOneSurface(int number_of_children) {
host_impl_.active_tree()->DetachLayers();
- std::unique_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl_.active_tree(), 1);
+ auto root = std::make_unique<TestLayerImpl>(host_impl_.active_tree(), 1);
root->SetBounds(gfx::Size(500, 500));
root->SetDrawsContent(true);
root->test_properties()->force_render_surface = true;
for (int i = 0; i < number_of_children; ++i) {
- std::unique_ptr<LayerImpl> child =
- LayerImpl::Create(host_impl_.active_tree(), 2 + i);
+ auto child =
+ std::make_unique<TestLayerImpl>(host_impl_.active_tree(), 2 + i);
child->test_properties()->position = gfx::PointF(100.f, 100.f);
child->SetBounds(gfx::Size(30, 30));
child->SetDrawsContent(true);
@@ -98,16 +127,13 @@ class DamageTrackerTest : public testing::Test {
// two children of its own.
host_impl_.active_tree()->DetachLayers();
- std::unique_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl_.active_tree(), 1);
- std::unique_ptr<LayerImpl> child1 =
- LayerImpl::Create(host_impl_.active_tree(), 2);
- std::unique_ptr<LayerImpl> child2 =
- LayerImpl::Create(host_impl_.active_tree(), 3);
- std::unique_ptr<LayerImpl> grand_child1 =
- LayerImpl::Create(host_impl_.active_tree(), 4);
- std::unique_ptr<LayerImpl> grand_child2 =
- LayerImpl::Create(host_impl_.active_tree(), 5);
+ auto root = std::make_unique<TestLayerImpl>(host_impl_.active_tree(), 1);
+ auto child1 = std::make_unique<TestLayerImpl>(host_impl_.active_tree(), 2);
+ auto child2 = std::make_unique<TestLayerImpl>(host_impl_.active_tree(), 3);
+ auto grand_child1 =
+ std::make_unique<TestLayerImpl>(host_impl_.active_tree(), 4);
+ auto grand_child2 =
+ std::make_unique<TestLayerImpl>(host_impl_.active_tree(), 5);
root->SetBounds(gfx::Size(500, 500));
root->SetDrawsContent(true);
@@ -276,7 +302,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) {
TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) {
LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
- LayerImpl* child = root->test_properties()->children[0];
+ auto* child =
+ static_cast<TestLayerImpl*>(root->test_properties()->children[0]);
// CASE 1: Adding the layer damage rect should cause the corresponding damage
// to the surface.
@@ -336,7 +363,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) {
TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) {
LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
- LayerImpl* child = root->test_properties()->children[0];
+ auto* child =
+ static_cast<TestLayerImpl*>(root->test_properties()->children[0]);
// CASE 1: Adding the layer damage rect and update rect should cause the
// corresponding damage to the surface.
@@ -547,9 +575,12 @@ TEST_F(DamageTrackerTest, TransformPropertyChangeNoSurface) {
TEST_F(DamageTrackerTest,
VerifyDamageForUpdateAndDamageRectsFromContributingContents) {
LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
- LayerImpl* child1 = root->test_properties()->children[0];
- LayerImpl* child2 = root->test_properties()->children[1];
- LayerImpl* grandchild1 = child1->test_properties()->children[0];
+ auto* child1 =
+ static_cast<TestLayerImpl*>(root->test_properties()->children[0]);
+ auto* child2 =
+ static_cast<TestLayerImpl*>(root->test_properties()->children[1]);
+ auto* grandchild1 =
+ static_cast<TestLayerImpl*>(child1->test_properties()->children[0]);
// CASE 1: Adding the layer1's damage rect and update rect should cause the
// corresponding damage to the surface.
@@ -1912,8 +1943,10 @@ TEST_F(DamageTrackerTest, DamageRectTooBigWithFilter) {
TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurface) {
LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
LayerImpl* child1 = root->test_properties()->children[0];
- LayerImpl* grandchild1 = child1->test_properties()->children[0];
- LayerImpl* grandchild2 = child1->test_properties()->children[1];
+ auto* grandchild1 =
+ static_cast<TestLayerImpl*>(child1->test_properties()->children[0]);
+ auto* grandchild2 =
+ static_cast<TestLayerImpl*>(child1->test_properties()->children[1]);
// Really far left.
grandchild1->test_properties()->position =
@@ -2002,8 +2035,10 @@ TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurface) {
TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurfaceWithFilter) {
LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
LayerImpl* child1 = root->test_properties()->children[0];
- LayerImpl* grandchild1 = child1->test_properties()->children[0];
- LayerImpl* grandchild2 = child1->test_properties()->children[1];
+ auto* grandchild1 =
+ static_cast<TestLayerImpl*>(child1->test_properties()->children[0]);
+ auto* grandchild2 =
+ static_cast<TestLayerImpl*>(child1->test_properties()->children[1]);
// Set up a moving pixels filter on the child.
FilterOperations filters;
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
index 9c1bec65c92..cf566cb9b6e 100644
--- a/chromium/cc/trees/draw_property_utils.cc
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -838,8 +838,17 @@ void FindLayersThatNeedUpdates(LayerTreeImpl* layer_tree_impl,
}
void ComputeTransforms(TransformTree* transform_tree) {
- if (!transform_tree->needs_update())
+ if (!transform_tree->needs_update()) {
+#if DCHECK_IS_ON()
+ // If the transform tree does not need an update, no TransformNode should
+ // need a local transform update.
+ for (int i = TransformTree::kContentsRootNodeId;
+ i < static_cast<int>(transform_tree->size()); ++i) {
+ DCHECK(!transform_tree->Node(i)->needs_local_transform_update);
+ }
+#endif
return;
+ }
for (int i = TransformTree::kContentsRootNodeId;
i < static_cast<int>(transform_tree->size()); ++i)
transform_tree->UpdateTransforms(i);
@@ -872,22 +881,11 @@ void UpdatePropertyTrees(LayerTreeHost* layer_tree_host,
}
void UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
- PropertyTrees* property_trees,
- bool can_adjust_raster_scales) {
- bool render_surfaces_need_update = false;
- if (property_trees->can_adjust_raster_scales != can_adjust_raster_scales) {
- property_trees->can_adjust_raster_scales = can_adjust_raster_scales;
- property_trees->transform_tree.set_needs_update(true);
- render_surfaces_need_update = true;
- }
+ PropertyTrees* property_trees) {
if (property_trees->transform_tree.needs_update()) {
property_trees->clip_tree.set_needs_update(true);
property_trees->effect_tree.set_needs_update(true);
}
- if (render_surfaces_need_update) {
- property_trees->effect_tree.UpdateRenderSurfaces(
- root_layer->layer_tree_impl());
- }
UpdateRenderTarget(&property_trees->effect_tree);
ComputeTransforms(&property_trees->transform_tree);
diff --git a/chromium/cc/trees/draw_property_utils.h b/chromium/cc/trees/draw_property_utils.h
index c37eaa0c066..6ca984986bd 100644
--- a/chromium/cc/trees/draw_property_utils.h
+++ b/chromium/cc/trees/draw_property_utils.h
@@ -44,8 +44,7 @@ void CC_EXPORT UpdatePropertyTrees(LayerTreeHost* layer_tree_host,
void CC_EXPORT
UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
- PropertyTrees* property_trees,
- bool can_adjust_raster_scales);
+ PropertyTrees* property_trees);
void CC_EXPORT FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host,
const PropertyTrees* property_trees,
diff --git a/chromium/cc/trees/effect_node.cc b/chromium/cc/trees/effect_node.cc
index 8c7a016eee4..847432950b3 100644
--- a/chromium/cc/trees/effect_node.cc
+++ b/chromium/cc/trees/effect_node.cc
@@ -57,6 +57,7 @@ bool EffectNode::operator==(const EffectNode& other) const {
filters == other.filters &&
backdrop_filters == other.backdrop_filters &&
backdrop_filter_bounds == other.backdrop_filter_bounds &&
+ backdrop_mask_element_id == other.backdrop_mask_element_id &&
filters_origin == other.filters_origin &&
rounded_corner_bounds == other.rounded_corner_bounds &&
is_fast_rounded_corner == other.is_fast_rounded_corner &&
@@ -142,10 +143,15 @@ const char* RenderSurfaceReasonToString(RenderSurfaceReason reason) {
}
void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const {
+ value->SetInteger("backdrop_mask_element_id",
+ backdrop_mask_element_id.GetInternalValue());
value->SetInteger("id", id);
value->SetInteger("parent_id", parent_id);
value->SetInteger("stable_id", stable_id);
value->SetDouble("opacity", opacity);
+ if (!backdrop_filters.IsEmpty()) {
+ value->SetString("backdrop_filters", backdrop_filters.ToString());
+ }
value->SetDouble("backdrop_filter_quality", backdrop_filter_quality);
value->SetBoolean("is_fast_rounded_corner", is_fast_rounded_corner);
if (!rounded_corner_bounds.IsEmpty()) {
diff --git a/chromium/cc/trees/effect_node.h b/chromium/cc/trees/effect_node.h
index 340305e9355..eaddb83fb4e 100644
--- a/chromium/cc/trees/effect_node.h
+++ b/chromium/cc/trees/effect_node.h
@@ -6,6 +6,7 @@
#define CC_TREES_EFFECT_NODE_H_
#include "cc/cc_export.h"
+#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "ui/gfx/geometry/point_f.h"
@@ -40,6 +41,7 @@ enum class RenderSurfaceReason : uint8_t {
kTrilinearFiltering,
kCache,
kCopyRequest,
+ kMirrored,
// This must be the last value because it's used in tracing code to know the
// number of reasons.
kTest,
@@ -73,6 +75,11 @@ struct CC_EXPORT EffectNode {
float backdrop_filter_quality;
gfx::PointF filters_origin;
+ // The element id corresponding to the mask to apply to the filtered backdrop
+ // image. Note that this is separate from mask_layer_id, which is a layer id,
+ // and is used for masking the "normal" (non-backdrop-filter) content.
+ ElementId backdrop_mask_element_id;
+
// Bounds of rounded corner rrect in the space of the transform node
// associated with this effect node.
gfx::RRectF rounded_corner_bounds;
diff --git a/chromium/cc/trees/frame_sequence_tracker.cc b/chromium/cc/trees/frame_sequence_tracker.cc
new file mode 100644
index 00000000000..a4020409e7a
--- /dev/null
+++ b/chromium/cc/trees/frame_sequence_tracker.cc
@@ -0,0 +1,390 @@
+// Copyright 2019 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/frame_sequence_tracker.h"
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/strcat.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/traced_value.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/quads/compositor_frame_metadata.h"
+#include "ui/gfx/presentation_feedback.h"
+
+namespace cc {
+
+namespace {
+
+enum class ThreadType {
+ kMain,
+ kCompositor,
+};
+
+constexpr const char* const kBuiltinSequences[] = {
+ [FrameSequenceTrackerType::kCompositorAnimation] = "CompositorAnimation",
+ [FrameSequenceTrackerType::kMainThreadAnimation] = "MainThreadAnimation",
+ [FrameSequenceTrackerType::kPinchZoom] = "PinchZoom",
+ [FrameSequenceTrackerType::kRAF] = "RAF",
+ [FrameSequenceTrackerType::kTouchScroll] = "TouchScroll",
+ [FrameSequenceTrackerType::kWheelScroll] = "WheelScroll",
+};
+
+constexpr int kBuiltinSequenceNum = base::size(kBuiltinSequences);
+constexpr int kMaximumHistogramIndex = 2 * kBuiltinSequenceNum;
+
+int GetIndexForMetric(ThreadType thread_type, FrameSequenceTrackerType type) {
+ return thread_type == ThreadType::kMain
+ ? static_cast<int>(type)
+ : static_cast<int>(type + kBuiltinSequenceNum);
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// FrameSequenceTrackerCollection
+
+FrameSequenceTrackerCollection::FrameSequenceTrackerCollection() {}
+FrameSequenceTrackerCollection::~FrameSequenceTrackerCollection() {
+ removal_trackers_.clear();
+ DCHECK(frame_trackers_.empty());
+}
+
+std::unique_ptr<FrameSequenceTracker>
+FrameSequenceTrackerCollection::CreateTracker(FrameSequenceTrackerType type) {
+ // The collection always outlives the trackers. So using Unretained() here is
+ // safe.
+ auto tracker = base::WrapUnique(new FrameSequenceTracker(
+ type, base::BindOnce(&FrameSequenceTrackerCollection::RemoveFrameTracker,
+ base::Unretained(this))));
+ AddFrameTracker(tracker.get());
+ return tracker;
+}
+
+void FrameSequenceTrackerCollection::ScheduleRemoval(
+ std::unique_ptr<FrameSequenceTracker> tracker) {
+ if (!tracker)
+ return;
+ tracker->ScheduleTerminate();
+ removal_trackers_.push_back(std::move(tracker));
+}
+
+void FrameSequenceTrackerCollection::ClearAll() {
+ removal_trackers_.clear();
+ DCHECK(frame_trackers_.empty());
+}
+
+void FrameSequenceTrackerCollection::NotifyBeginImplFrame(
+ const viz::BeginFrameArgs& args) {
+ for (auto* tracker : frame_trackers_) {
+ tracker->ReportBeginImplFrame(args);
+ }
+}
+
+void FrameSequenceTrackerCollection::NotifyBeginMainFrame(
+ const viz::BeginFrameArgs& args) {
+ for (auto* tracker : frame_trackers_) {
+ tracker->ReportBeginMainFrame(args);
+ }
+}
+
+void FrameSequenceTrackerCollection::NotifyImplFrameCausedNoDamage(
+ const viz::BeginFrameAck& ack) {
+ for (auto* tracker : frame_trackers_) {
+ tracker->ReportImplFrameCausedNoDamage(ack);
+ }
+}
+
+void FrameSequenceTrackerCollection::NotifyMainFrameCausedNoDamage(
+ const viz::BeginFrameArgs& args) {
+ for (auto* tracker : frame_trackers_) {
+ tracker->ReportMainFrameCausedNoDamage(args);
+ }
+}
+
+void FrameSequenceTrackerCollection::NotifyPauseFrameProduction() {
+ for (auto* tracker : frame_trackers_)
+ tracker->PauseFrameProduction();
+}
+
+void FrameSequenceTrackerCollection::NotifySubmitFrame(
+ uint32_t frame_token,
+ const viz::BeginFrameAck& ack,
+ const viz::BeginFrameArgs& origin_args) {
+ for (auto* tracker : frame_trackers_) {
+ tracker->ReportSubmitFrame(frame_token, ack, origin_args);
+ }
+}
+
+void FrameSequenceTrackerCollection::NotifyFramePresented(
+ uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback) {
+ for (auto* tracker : frame_trackers_)
+ tracker->ReportFramePresented(frame_token, feedback);
+
+ // Destroy the trackers that are ready to be terminated.
+ base::EraseIf(
+ removal_trackers_,
+ [](const std::unique_ptr<FrameSequenceTracker>& tracker) {
+ return tracker->termination_status() ==
+ FrameSequenceTracker::TerminationStatus::kReadyForTermination;
+ });
+}
+
+void FrameSequenceTrackerCollection::AddFrameTracker(
+ FrameSequenceTracker* tracker) {
+ frame_trackers_.push_back(tracker);
+}
+
+void FrameSequenceTrackerCollection::RemoveFrameTracker(
+ FrameSequenceTracker* tracker) {
+ base::Erase(frame_trackers_, tracker);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FrameSequenceTracker
+
+FrameSequenceTracker::FrameSequenceTracker(
+ FrameSequenceTrackerType type,
+ base::OnceCallback<void(FrameSequenceTracker*)> destroy_callback)
+ : type_(type), destroy_callback_(std::move(destroy_callback)) {
+ DCHECK_LT(type_, FrameSequenceTrackerType::kMaxType);
+ TRACE_EVENT_ASYNC_BEGIN1("cc,benchmark", "FrameSequenceTracker", this, "name",
+ TRACE_STR_COPY(kBuiltinSequences[type_]));
+}
+
+FrameSequenceTracker::~FrameSequenceTracker() {
+ DCHECK_LE(impl_throughput_.frames_produced, impl_throughput_.frames_expected);
+ DCHECK_LE(main_throughput_.frames_produced, main_throughput_.frames_expected);
+ DCHECK_LE(main_throughput_.frames_produced, impl_throughput_.frames_produced);
+ TRACE_EVENT_ASYNC_END1(
+ "cc,benchmark", "FrameSequenceTracker", this, "args",
+ ThroughputData::ToTracedValue(impl_throughput_, main_throughput_));
+ ThroughputData::ReportHistogram(
+ type_, "CompositorThread",
+ GetIndexForMetric(ThreadType::kCompositor, type_), impl_throughput_);
+ ThroughputData::ReportHistogram(type_, "MainThread",
+ GetIndexForMetric(ThreadType::kMain, type_),
+ main_throughput_);
+ std::move(destroy_callback_).Run(this);
+}
+
+void FrameSequenceTracker::ReportBeginImplFrame(
+ const viz::BeginFrameArgs& args) {
+ if (termination_status_ != TerminationStatus::kActive)
+ return;
+
+ if (ShouldIgnoreBeginFrameSource(args.source_id))
+ return;
+
+ UpdateTrackedFrameData(&begin_impl_frame_data_, args.source_id,
+ args.sequence_number);
+ impl_throughput_.frames_expected +=
+ begin_impl_frame_data_.previous_sequence_delta;
+}
+
+void FrameSequenceTracker::ReportBeginMainFrame(
+ const viz::BeginFrameArgs& args) {
+ if (termination_status_ != TerminationStatus::kActive)
+ return;
+
+ if (ShouldIgnoreBeginFrameSource(args.source_id))
+ return;
+
+ UpdateTrackedFrameData(&begin_main_frame_data_, args.source_id,
+ args.sequence_number);
+ if (first_received_main_sequence_ == 0)
+ first_received_main_sequence_ = args.sequence_number;
+ main_throughput_.frames_expected +=
+ begin_main_frame_data_.previous_sequence_delta;
+}
+
+void FrameSequenceTracker::ReportSubmitFrame(
+ uint32_t frame_token,
+ const viz::BeginFrameAck& ack,
+ const viz::BeginFrameArgs& origin_args) {
+ if (termination_status_ != TerminationStatus::kActive)
+ return;
+
+ if (ShouldIgnoreBeginFrameSource(ack.source_id))
+ return;
+
+ if (begin_impl_frame_data_.previous_sequence == 0 ||
+ ack.sequence_number < begin_impl_frame_data_.previous_sequence) {
+ return;
+ }
+
+ if (first_submitted_frame_ == 0)
+ first_submitted_frame_ = frame_token;
+ last_submitted_frame_ = frame_token;
+
+ if (!ShouldIgnoreBeginFrameSource(origin_args.source_id) &&
+ first_received_main_sequence_ &&
+ origin_args.sequence_number >= first_received_main_sequence_) {
+ if (last_submitted_main_sequence_ == 0 ||
+ origin_args.sequence_number > last_submitted_main_sequence_) {
+ last_submitted_main_sequence_ = origin_args.sequence_number;
+ main_frames_.push_back(frame_token);
+ DCHECK_GE(main_throughput_.frames_expected, main_frames_.size());
+ }
+ }
+}
+
+void FrameSequenceTracker::ReportFramePresented(
+ uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback) {
+ const bool frame_token_acks_last_frame =
+ frame_token == last_submitted_frame_ ||
+ viz::FrameTokenGT(frame_token, last_submitted_frame_);
+
+ // Update termination status if this is scheduled for termination, and it is
+ // not waiting for any frames, or it has received the presentation-feedback
+ // for the latest frame it is tracking.
+ if (termination_status_ == TerminationStatus::kScheduledForTermination &&
+ (last_submitted_frame_ == 0 || frame_token_acks_last_frame)) {
+ termination_status_ = TerminationStatus::kReadyForTermination;
+ }
+
+ if (first_submitted_frame_ == 0 ||
+ viz::FrameTokenGT(first_submitted_frame_, frame_token)) {
+ // We are getting presentation feedback for frames that were submitted
+ // before this sequence started. So ignore these.
+ return;
+ }
+
+ const bool was_presented = !feedback.timestamp.is_null();
+ if (was_presented && last_submitted_frame_) {
+ DCHECK_LT(impl_throughput_.frames_produced,
+ impl_throughput_.frames_expected);
+ ++impl_throughput_.frames_produced;
+
+ if (frame_token_acks_last_frame)
+ last_submitted_frame_ = 0;
+ }
+
+ while (!main_frames_.empty() &&
+ !viz::FrameTokenGT(main_frames_.front(), frame_token)) {
+ if (was_presented && main_frames_.front() == frame_token) {
+ DCHECK_LT(main_throughput_.frames_produced,
+ main_throughput_.frames_expected);
+ ++main_throughput_.frames_produced;
+ }
+ main_frames_.pop_front();
+ }
+}
+
+void FrameSequenceTracker::ReportImplFrameCausedNoDamage(
+ const viz::BeginFrameAck& ack) {
+ if (termination_status_ != TerminationStatus::kActive)
+ return;
+
+ if (ShouldIgnoreBeginFrameSource(ack.source_id))
+ return;
+
+ // It is possible that this is called before a begin-impl-frame has been
+ // dispatched for this frame-sequence. In such cases, ignore this call.
+ if (begin_impl_frame_data_.previous_sequence == 0 ||
+ ack.sequence_number < begin_impl_frame_data_.previous_sequence) {
+ return;
+ }
+ DCHECK_GT(impl_throughput_.frames_expected, 0u);
+ DCHECK_GT(impl_throughput_.frames_expected, impl_throughput_.frames_produced);
+ --impl_throughput_.frames_expected;
+
+ if (begin_impl_frame_data_.previous_sequence == ack.sequence_number)
+ begin_impl_frame_data_.previous_sequence = 0;
+}
+
+void FrameSequenceTracker::ReportMainFrameCausedNoDamage(
+ const viz::BeginFrameArgs& args) {
+ if (termination_status_ != TerminationStatus::kActive)
+ return;
+
+ if (ShouldIgnoreBeginFrameSource(args.source_id))
+ return;
+
+ // It is possible that this is called before a begin-main-frame has been
+ // dispatched for this frame-sequence. In such cases, ignore this call.
+ if (begin_main_frame_data_.previous_sequence == 0 ||
+ args.sequence_number < begin_main_frame_data_.previous_sequence) {
+ return;
+ }
+
+ DCHECK_GT(main_throughput_.frames_expected, 0u);
+ DCHECK_GT(main_throughput_.frames_expected, main_throughput_.frames_produced);
+ --main_throughput_.frames_expected;
+ DCHECK_GE(main_throughput_.frames_expected, main_frames_.size());
+
+ if (begin_main_frame_data_.previous_sequence == args.sequence_number)
+ begin_main_frame_data_.previous_sequence = 0;
+}
+
+void FrameSequenceTracker::PauseFrameProduction() {
+ // Reset the states, so that the tracker ignores the vsyncs until the next
+ // received begin-frame.
+ begin_impl_frame_data_ = {0, 0, 0};
+ begin_main_frame_data_ = {0, 0, 0};
+}
+
+void FrameSequenceTracker::UpdateTrackedFrameData(TrackedFrameData* frame_data,
+ uint64_t source_id,
+ uint64_t sequence_number) {
+ if (frame_data->previous_sequence &&
+ frame_data->previous_source == source_id) {
+ uint8_t current_latency = sequence_number - frame_data->previous_sequence;
+ frame_data->previous_sequence_delta = current_latency;
+ } else {
+ frame_data->previous_sequence_delta = 1;
+ }
+ frame_data->previous_source = source_id;
+ frame_data->previous_sequence = sequence_number;
+}
+
+bool FrameSequenceTracker::ShouldIgnoreBeginFrameSource(
+ uint64_t source_id) const {
+ if (begin_impl_frame_data_.previous_source == 0)
+ return false;
+ return source_id != begin_impl_frame_data_.previous_source;
+}
+
+std::unique_ptr<base::trace_event::TracedValue>
+FrameSequenceTracker::ThroughputData::ToTracedValue(
+ const ThroughputData& impl,
+ const ThroughputData& main) {
+ auto dict = std::make_unique<base::trace_event::TracedValue>();
+ dict->SetInteger("impl-frames-produced", impl.frames_produced);
+ dict->SetInteger("impl-frames-expected", impl.frames_expected);
+ dict->SetInteger("main-frames-produced", main.frames_produced);
+ dict->SetInteger("main-frames-expected", main.frames_expected);
+ return dict;
+}
+
+void FrameSequenceTracker::ThroughputData::ReportHistogram(
+ FrameSequenceTrackerType sequence_type,
+ const char* thread_name,
+ int metric_index,
+ const ThroughputData& data) {
+ DCHECK_LT(sequence_type, FrameSequenceTrackerType::kMaxType);
+
+ UMA_HISTOGRAM_COUNTS_1000("Graphics.Smoothness.FrameSequenceLength",
+ data.frames_expected);
+
+ // Avoid reporting any throughput metric for sequences that had a small amount
+ // of frames.
+ constexpr int kMinFramesForThroughputMetric = 4;
+ if (data.frames_expected < kMinFramesForThroughputMetric)
+ return;
+
+ const std::string name =
+ base::StrCat({"Graphics.Smoothness.Throughput.", thread_name, ".",
+ kBuiltinSequences[sequence_type]});
+ const int percent =
+ static_cast<int>(100 * data.frames_produced / data.frames_expected);
+ STATIC_HISTOGRAM_POINTER_GROUP(
+ name, metric_index, kMaximumHistogramIndex, Add(percent),
+ base::LinearHistogram::FactoryGet(
+ name, 1, 100, 101, base::HistogramBase::kUmaTargetedHistogramFlag));
+}
+
+} // namespace cc
diff --git a/chromium/cc/trees/frame_sequence_tracker.h b/chromium/cc/trees/frame_sequence_tracker.h
new file mode 100644
index 00000000000..57b370eb316
--- /dev/null
+++ b/chromium/cc/trees/frame_sequence_tracker.h
@@ -0,0 +1,238 @@
+// Copyright 2019 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.
+
+#ifndef CC_TREES_FRAME_SEQUENCE_TRACKER_H_
+#define CC_TREES_FRAME_SEQUENCE_TRACKER_H_
+
+#include <stdint.h>
+#include <memory>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/callback_helpers.h"
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "base/trace_event/traced_value.h"
+#include "cc/cc_export.h"
+
+namespace gfx {
+struct PresentationFeedback;
+}
+
+namespace viz {
+struct BeginFrameAck;
+struct BeginFrameArgs;
+} // namespace viz
+
+namespace cc {
+class FrameSequenceTracker;
+
+enum FrameSequenceTrackerType {
+ kCompositorAnimation,
+ kMainThreadAnimation,
+ kPinchZoom,
+ kRAF,
+ kTouchScroll,
+ kWheelScroll,
+ kMaxType
+};
+
+// Used for notifying attached FrameSequenceTracker's of begin-frames and
+// submitted frames.
+class CC_EXPORT FrameSequenceTrackerCollection {
+ public:
+ FrameSequenceTrackerCollection();
+ ~FrameSequenceTrackerCollection();
+
+ FrameSequenceTrackerCollection(const FrameSequenceTrackerCollection&) =
+ delete;
+ FrameSequenceTrackerCollection& operator=(
+ const FrameSequenceTrackerCollection&) = delete;
+
+ // Creates a tracker for the specified sequence-type.
+ std::unique_ptr<FrameSequenceTracker> CreateTracker(
+ FrameSequenceTrackerType type);
+
+ // Schedules |tracker| for destruction. This is preferred instead of outright
+ // desrtruction of the tracker, since this ensures that the actual tracker
+ // instance is destroyed *after* the presentation-feedbacks have been received
+ // for all submitted frames.
+ void ScheduleRemoval(std::unique_ptr<FrameSequenceTracker> tracker);
+
+ // Removes all trackers. This also immediately destroys all trackers that had
+ // been scheduled for destruction, even if there are pending
+ // presentation-feedbacks. This is typically used if the client no longer
+ // expects to receive presentation-feedbacks for the previously submitted
+ // frames (e.g. when the gpu process dies).
+ void ClearAll();
+
+ // Notifies all trackers of various events.
+ void NotifyBeginImplFrame(const viz::BeginFrameArgs& args);
+ void NotifyBeginMainFrame(const viz::BeginFrameArgs& args);
+ void NotifyImplFrameCausedNoDamage(const viz::BeginFrameAck& ack);
+ void NotifyMainFrameCausedNoDamage(const viz::BeginFrameArgs& args);
+ void NotifyPauseFrameProduction();
+ void NotifySubmitFrame(uint32_t frame_token,
+ const viz::BeginFrameAck& ack,
+ const viz::BeginFrameArgs& origin_args);
+
+ // Note that this notifies the trackers of the presentation-feedbacks, and
+ // destroys any tracker that had been scheduled for destruction (using
+ // |ScheduleRemoval()|) if it has no more pending frames.
+ void NotifyFramePresented(uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback);
+
+ private:
+ void AddFrameTracker(FrameSequenceTracker* tracker);
+ void RemoveFrameTracker(FrameSequenceTracker* tracker);
+
+ std::vector<FrameSequenceTracker*> frame_trackers_;
+ std::vector<std::unique_ptr<FrameSequenceTracker>> removal_trackers_;
+};
+
+// Tracks a sequence of frames to determine the throughput. It tracks this by
+// tracking the vsync sequence-numbers (from |BeginFrameArgs::sequence_number|),
+// and the presentation-timestamps (from |gfx::PresentationFeedback|). It also
+// tracks which frames were expected to include update from the main-thread, and
+// which presented frames did include updates from the main-thread.
+// This object should be created through
+// FrameSequenceTrackerCollection::CreateTracker() API.
+class CC_EXPORT FrameSequenceTracker {
+ public:
+ enum class TerminationStatus {
+ kActive,
+ kScheduledForTermination,
+ kReadyForTermination,
+ };
+
+ ~FrameSequenceTracker();
+
+ FrameSequenceTracker(const FrameSequenceTracker&) = delete;
+ FrameSequenceTracker& operator=(const FrameSequenceTracker&) = delete;
+
+ // Notifies the tracker when the compositor thread starts to process a
+ // BeginFrameArgs.
+ void ReportBeginImplFrame(const viz::BeginFrameArgs& args);
+
+ // Notifies the tracker when a BeginFrameArgs is dispatched to the main
+ // thread.
+ void ReportBeginMainFrame(const viz::BeginFrameArgs& args);
+
+ // Notifies the tracker when the compositor submits a CompositorFrame.
+ // |origin_args| represents the BeginFrameArgs that triggered the update from
+ // the main-thread.
+ void ReportSubmitFrame(uint32_t frame_token,
+ const viz::BeginFrameAck& ack,
+ const viz::BeginFrameArgs& origin_args);
+
+ // Notifies the tracker of the presentation-feedback of a previously submitted
+ // CompositorFrame with |frame_token|.
+ void ReportFramePresented(uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback);
+
+ // Notifies the tracker that a CompositorFrame is not going to be submitted
+ // for a particular BeginFrameArgs because it did not cause any damage (visual
+ // change). Note that if a begin-main-frame was dispatched, then a separate
+ // call to |ReportMainFrameCausedNoDamage()| is made to notify that the
+ // main-thread did not cause any damage/updates.
+ void ReportImplFrameCausedNoDamage(const viz::BeginFrameAck& ack);
+
+ // Notifies the tracker that a |BeginFrameArgs| either was not dispatched to
+ // the main-thread (because it did not ask for it), or that a |BeginFrameArgs|
+ // that was dispatched to the main-thread did not cause any updates/damage.
+ void ReportMainFrameCausedNoDamage(const viz::BeginFrameArgs& args);
+
+ // Notifies that frame production has currently paused. This is typically used
+ // for interactive frame-sequences, e.g. during touch-scroll.
+ void PauseFrameProduction();
+
+ TerminationStatus termination_status() const { return termination_status_; }
+
+ private:
+ friend class FrameSequenceTrackerCollection;
+
+ FrameSequenceTracker(
+ FrameSequenceTrackerType type,
+ base::OnceCallback<void(FrameSequenceTracker*)> destroy_callback);
+
+ void ScheduleTerminate() {
+ termination_status_ = TerminationStatus::kScheduledForTermination;
+ }
+
+ struct TrackedFrameData {
+ // Represents the |BeginFrameArgs::source_id| and
+ // |BeginFrameArgs::sequence_number| fields of the last processed
+ // BeginFrameArgs.
+ uint64_t previous_source = 0;
+ uint64_t previous_sequence = 0;
+
+ // The difference in |BeginFrameArgs::sequence_number| fields of the last
+ // two processed BeginFrameArgs.
+ uint8_t previous_sequence_delta = 0;
+ };
+
+ struct ThroughputData {
+ static std::unique_ptr<base::trace_event::TracedValue> ToTracedValue(
+ const ThroughputData& impl,
+ const ThroughputData& main);
+ static void ReportHistogram(FrameSequenceTrackerType sequence_type,
+ const char* thread_name,
+ int metric_index,
+ const ThroughputData& data);
+ // Tracks the number of frames that were expected to be shown during this
+ // frame-sequence.
+ uint32_t frames_expected = 0;
+
+ // Tracks the number of frames that were actually presented to the user
+ // during this frame-sequence.
+ uint32_t frames_produced = 0;
+ };
+
+ void UpdateTrackedFrameData(TrackedFrameData* frame_data,
+ uint64_t source_id,
+ uint64_t sequence_number);
+
+ bool ShouldIgnoreBeginFrameSource(uint64_t source_id) const;
+
+ const FrameSequenceTrackerType type_;
+ base::OnceCallback<void(FrameSequenceTracker*)> destroy_callback_;
+
+ TerminationStatus termination_status_ = TerminationStatus::kActive;
+
+ TrackedFrameData begin_impl_frame_data_;
+ TrackedFrameData begin_main_frame_data_;
+
+ ThroughputData impl_throughput_;
+ ThroughputData main_throughput_;
+
+ // Tracks the list of frame-tokens for compositor-frames that included new
+ // updates from the main-thread, whose presentation-feedback have not been
+ // received yet. When the presentation-feedback for a frame is received, the
+ // corresponding frame-token is removed from this collection.
+ base::circular_deque<uint32_t> main_frames_;
+
+ // Keeps track of the sequence-number of the first received begin-main-frame.
+ // This is used to ignore submitted frames that include updates from earlier
+ // begin-main-frames.
+ uint64_t first_received_main_sequence_ = 0;
+
+ // Keeps track of the first submitted compositor-frame. This is used to ignore
+ // reports from frames that were submitted before this tracker had been
+ // created.
+ uint32_t first_submitted_frame_ = 0;
+
+ // Keeps track of the latest submitted compositor-frame, so that it can
+ // determine when it has received presentation-feedback for submitted frames.
+ // This is used to decide when to terminate this FrameSequenceTracker object.
+ uint32_t last_submitted_frame_ = 0;
+
+ // Keeps track of the last sequence-number that produced a frame from the
+ // main-thread.
+ uint64_t last_submitted_main_sequence_ = 0;
+};
+
+} // namespace cc
+
+#endif // CC_TREES_FRAME_SEQUENCE_TRACKER_H_
diff --git a/chromium/cc/trees/frame_sequence_tracker_unittest.cc b/chromium/cc/trees/frame_sequence_tracker_unittest.cc
new file mode 100644
index 00000000000..1de4c9c38a9
--- /dev/null
+++ b/chromium/cc/trees/frame_sequence_tracker_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright 2019 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/frame_sequence_tracker.h"
+
+#include "base/macros.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class FrameSequenceTrackerTest;
+
+class FrameSequenceTrackerTest : public testing::Test {
+ public:
+ const uint32_t kImplDamage = 0x1;
+ const uint32_t kMainDamage = 0x2;
+
+ FrameSequenceTrackerTest()
+ : tracker_(
+ collection_.CreateTracker(FrameSequenceTrackerType::kTouchScroll)) {
+ }
+ ~FrameSequenceTrackerTest() override = default;
+
+ std::unique_ptr<FrameSequenceTracker> CreateNewTracker() {
+ return collection_.CreateTracker(FrameSequenceTrackerType::kTouchScroll);
+ }
+
+ viz::BeginFrameArgs CreateBeginFrameArgs(uint64_t source_id,
+ uint64_t sequence_number) {
+ auto now = base::TimeTicks::Now();
+ auto interval = base::TimeDelta::FromMilliseconds(16);
+ auto deadline = now + interval;
+ return viz::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, source_id,
+ sequence_number, now, deadline, interval,
+ viz::BeginFrameArgs::NORMAL);
+ }
+
+ void StartImplAndMainFrames(const viz::BeginFrameArgs& args) {
+ collection_.NotifyBeginImplFrame(args);
+ collection_.NotifyBeginMainFrame(args);
+ }
+
+ uint32_t DispatchCompleteFrame(const viz::BeginFrameArgs& args,
+ uint32_t damage_type) {
+ StartImplAndMainFrames(args);
+
+ if (damage_type & kImplDamage) {
+ if (!(damage_type & kMainDamage)) {
+ collection_.NotifyMainFrameCausedNoDamage(args);
+ }
+ uint32_t frame_token = NextFrameToken();
+ collection_.NotifySubmitFrame(frame_token, viz::BeginFrameAck(args, true),
+ args);
+ return frame_token;
+ } else {
+ collection_.NotifyImplFrameCausedNoDamage(
+ viz::BeginFrameAck(args, false));
+ collection_.NotifyMainFrameCausedNoDamage(args);
+ }
+ return 0;
+ }
+
+ uint32_t NextFrameToken() {
+ static uint32_t frame_token = 0;
+ return ++frame_token;
+ }
+
+ protected:
+ FrameSequenceTrackerCollection collection_;
+
+ std::unique_ptr<FrameSequenceTracker> tracker_;
+};
+
+// Tests that the tracker works correctly when the source-id for the
+// begin-frames change.
+TEST_F(FrameSequenceTrackerTest, SourceIdChangeDuringSequence) {
+ const uint64_t source_1 = 1;
+ uint64_t sequence_1 = 0;
+
+ // Dispatch some frames, both causing damage to impl/main, and both impl and
+ // main providing damage to the frame.
+ auto args_1 = CreateBeginFrameArgs(source_1, ++sequence_1);
+ DispatchCompleteFrame(args_1, kImplDamage | kMainDamage);
+ args_1 = CreateBeginFrameArgs(source_1, ++sequence_1);
+ DispatchCompleteFrame(args_1, kImplDamage | kMainDamage);
+
+ // Start a new tracker.
+ auto tracker = CreateNewTracker();
+
+ // Change the source-id, and start an impl frame. This time, the main-frame
+ // does not provide any damage.
+ const uint64_t source_2 = 2;
+ uint64_t sequence_2 = 0;
+ auto args_2 = CreateBeginFrameArgs(source_2, ++sequence_2);
+ collection_.NotifyBeginImplFrame(args_2);
+ collection_.NotifyBeginMainFrame(args_2);
+ collection_.NotifyMainFrameCausedNoDamage(args_2);
+ // Since the main-frame did not have any new damage from the latest
+ // BeginFrameArgs, the submit-frame will carry the previous BeginFrameArgs
+ // (from source_1);
+ collection_.NotifySubmitFrame(NextFrameToken(),
+ viz::BeginFrameAck(args_2, true), args_1);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/trees/image_animation_controller.cc b/chromium/cc/trees/image_animation_controller.cc
index eb92e3b4f5f..a7e1ebf6de6 100644
--- a/chromium/cc/trees/image_animation_controller.cc
+++ b/chromium/cc/trees/image_animation_controller.cc
@@ -454,7 +454,7 @@ size_t ImageAnimationController::AnimationState::NextFrameIndex() const {
ImageAnimationController::InvalidationScheduler::InvalidationScheduler(
base::SingleThreadTaskRunner* task_runner,
Client* client)
- : task_runner_(task_runner), client_(client), weak_factory_(this) {
+ : task_runner_(task_runner), client_(client) {
DCHECK(task_runner_->BelongsToCurrentThread());
}
diff --git a/chromium/cc/trees/image_animation_controller.h b/chromium/cc/trees/image_animation_controller.h
index a95ec12448e..1f118704810 100644
--- a/chromium/cc/trees/image_animation_controller.h
+++ b/chromium/cc/trees/image_animation_controller.h
@@ -267,7 +267,7 @@ class CC_EXPORT ImageAnimationController {
// The time at which the next animation is expected to run.
base::TimeTicks next_animation_time_;
- base::WeakPtrFactory<InvalidationScheduler> weak_factory_;
+ base::WeakPtrFactory<InvalidationScheduler> weak_factory_{this};
};
// The AnimationState for images is persisted until they are cleared on
diff --git a/chromium/cc/trees/layer_tree_frame_sink.cc b/chromium/cc/trees/layer_tree_frame_sink.cc
index 71ed2774860..34ac5b7dfa5 100644
--- a/chromium/cc/trees/layer_tree_frame_sink.cc
+++ b/chromium/cc/trees/layer_tree_frame_sink.cc
@@ -48,8 +48,7 @@ LayerTreeFrameSink::LayerTreeFrameSink(
: context_provider_(std::move(context_provider)),
worker_context_provider_(std::move(worker_context_provider)),
compositor_task_runner_(std::move(compositor_task_runner)),
- gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
- weak_ptr_factory_(this) {
+ gpu_memory_buffer_manager_(gpu_memory_buffer_manager) {
DETACH_FROM_THREAD(thread_checker_);
}
diff --git a/chromium/cc/trees/layer_tree_frame_sink.h b/chromium/cc/trees/layer_tree_frame_sink.h
index 76634a79771..68b9734737a 100644
--- a/chromium/cc/trees/layer_tree_frame_sink.h
+++ b/chromium/cc/trees/layer_tree_frame_sink.h
@@ -8,6 +8,7 @@
#include <deque>
#include <memory>
+#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
@@ -127,7 +128,7 @@ class CC_EXPORT LayerTreeFrameSink : public viz::SharedBitmapReporter,
virtual void DidNotProduceFrame(const viz::BeginFrameAck& ack) = 0;
// viz::SharedBitmapReporter implementation.
- void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
+ void DidAllocateSharedBitmap(base::ReadOnlySharedMemoryRegion region,
const viz::SharedBitmapId& id) override = 0;
void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override = 0;
@@ -154,7 +155,7 @@ class CC_EXPORT LayerTreeFrameSink : public viz::SharedBitmapReporter,
private:
THREAD_CHECKER(thread_checker_);
- base::WeakPtrFactory<LayerTreeFrameSink> weak_ptr_factory_;
+ base::WeakPtrFactory<LayerTreeFrameSink> weak_ptr_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_frame_sink_client.h b/chromium/cc/trees/layer_tree_frame_sink_client.h
index fc298c8fef5..50848593309 100644
--- a/chromium/cc/trees/layer_tree_frame_sink_client.h
+++ b/chromium/cc/trees/layer_tree_frame_sink_client.h
@@ -68,9 +68,6 @@ class CC_EXPORT LayerTreeFrameSinkClient {
// viz::ContextProviders) must be recreated.
virtual void DidLoseLayerTreeFrameSink() = 0;
- // Notification that the client does not need a new BeginFrame.
- virtual void DidNotNeedBeginFrame() = 0;
-
// For SynchronousCompositor (WebView) to ask the layer compositor to submit
// a new CompositorFrame synchronously.
virtual void OnDraw(const gfx::Transform& transform,
diff --git a/chromium/cc/trees/layer_tree_frame_sink_unittest.cc b/chromium/cc/trees/layer_tree_frame_sink_unittest.cc
index 58334b8322f..5eabeb0a5dc 100644
--- a/chromium/cc/trees/layer_tree_frame_sink_unittest.cc
+++ b/chromium/cc/trees/layer_tree_frame_sink_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/trees/layer_tree_frame_sink.h"
+#include "base/memory/read_only_shared_memory_region.h"
#include "base/single_thread_task_runner.h"
#include "base/test/test_simple_task_runner.h"
#include "cc/test/fake_layer_tree_frame_sink_client.h"
@@ -34,7 +35,7 @@ class StubLayerTreeFrameSink : public LayerTreeFrameSink {
client_->DidReceiveCompositorFrameAck();
}
void DidNotProduceFrame(const viz::BeginFrameAck& ack) override {}
- void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
+ void DidAllocateSharedBitmap(base::ReadOnlySharedMemoryRegion region,
const viz::SharedBitmapId& id) override {}
void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override {}
};
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index 4e9a9393289..5270f43d422 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -131,10 +131,8 @@ LayerTreeHost::LayerTreeHost(InitParams params, CompositorMode mode)
debug_state_(settings_.initial_debug_state),
id_(s_layer_tree_host_sequence_number.GetNext() + 1),
task_graph_runner_(params.task_graph_runner),
- content_source_id_(0),
event_listener_properties_(),
- mutator_host_(params.mutator_host),
- defer_main_frame_update_weak_ptr_factory_(this) {
+ mutator_host_(params.mutator_host) {
DCHECK(task_graph_runner_);
DCHECK(!settings_.enable_checker_imaging || image_worker_task_runner_);
@@ -392,7 +390,11 @@ void LayerTreeHost::FinishCommitOnImplThread(
// Dump property trees and layers if run with:
// --vmodule=layer_tree_host=3
if (VLOG_IS_ON(3)) {
- VLOG(3) << "After finishing commit on impl, the sync tree:"
+ const char* client_name = GetClientNameForMetrics();
+ if (!client_name)
+ client_name = "<unknown client>";
+ VLOG(3) << "After finishing (" << client_name
+ << ") commit on impl, the sync tree:"
<< "\nproperty_trees:\n"
<< sync_tree->property_trees()->ToString() << "\n"
<< "cc::LayerImpls:\n"
@@ -769,7 +771,7 @@ std::string LayerTreeHost::LayersAsString() const {
return layers;
}
-bool LayerTreeHost::CaptureContent(std::vector<NodeHolder>* content) {
+bool LayerTreeHost::CaptureContent(std::vector<NodeId>* content) {
if (viewport_visible_rect_.IsEmpty())
return false;
@@ -914,15 +916,9 @@ void LayerTreeHost::ApplyViewportChanges(const ScrollAndScaleSet& info) {
SetNeedsUpdateLayers();
}
-void LayerTreeHost::RecordWheelAndTouchScrollingCount(
- const ScrollAndScaleSet& info) {
- bool has_scrolled_by_wheel = info.has_scrolled_by_wheel;
- bool has_scrolled_by_touch = info.has_scrolled_by_touch;
-
- if (has_scrolled_by_wheel || has_scrolled_by_touch) {
- client_->RecordWheelAndTouchScrollingCount(has_scrolled_by_wheel,
- has_scrolled_by_touch);
- }
+void LayerTreeHost::RecordManipulationTypeCounts(
+ const ScrollAndScaleSet& scroll_info) {
+ client_->RecordManipulationTypeCounts(scroll_info.manipulation_info);
}
void LayerTreeHost::SendOverscrollAndScrollEndEventsFromImplSide(
@@ -972,7 +968,7 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) {
// on the main thread.
ApplyViewportChanges(*info);
- RecordWheelAndTouchScrollingCount(*info);
+ RecordManipulationTypeCounts(*info);
}
void LayerTreeHost::RecordStartOfFrameMetrics() {
@@ -1343,10 +1339,6 @@ void LayerTreeHost::SetExternalPageScaleFactor(
SetNeedsCommit();
}
-void LayerTreeHost::SetContentSourceId(uint32_t id) {
- content_source_id_ = id;
-}
-
void LayerTreeHost::ClearCachesOnNextCommit() {
clear_caches_on_next_commit_ = true;
}
@@ -1606,8 +1598,6 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) {
tree_impl->SetRasterColorSpace(raster_color_space_id_, raster_color_space_);
tree_impl->SetExternalPageScaleFactor(external_page_scale_factor_);
- tree_impl->set_content_source_id(content_source_id_);
-
tree_impl->set_painted_device_scale_factor(painted_device_scale_factor_);
tree_impl->SetDeviceScaleFactor(device_scale_factor_);
tree_impl->SetDeviceViewportSize(device_viewport_size_);
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index b7cf9d9af7d..54000cfece0 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -33,7 +33,7 @@
#include "cc/input/scrollbar.h"
#include "cc/layers/layer_collections.h"
#include "cc/layers/layer_list_iterator.h"
-#include "cc/paint/node_holder.h"
+#include "cc/paint/node_id.h"
#include "cc/trees/compositor_mode.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_host_client.h"
@@ -432,9 +432,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
return painted_device_scale_factor_;
}
- void SetContentSourceId(uint32_t);
- uint32_t content_source_id() const { return content_source_id_; }
-
// Clears image caches and resets the scheduling history for the content
// produced by this host so far.
void ClearCachesOnNextCommit();
@@ -678,8 +675,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
std::string LayersAsString() const;
// Captures the on-screen text content, if success, fills the associated
- // NodeHolder in |content| and return true, otherwise return false.
- bool CaptureContent(std::vector<NodeHolder>* content);
+ // NodeId in |content| and return true, otherwise return false.
+ bool CaptureContent(std::vector<NodeId>* content);
protected:
LayerTreeHost(InitParams params, CompositorMode mode);
@@ -722,7 +719,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
enum { kNumFramesToConsiderBeforeRemovingSlowPathFlag = 60 };
void ApplyViewportChanges(const ScrollAndScaleSet& info);
- void RecordWheelAndTouchScrollingCount(const ScrollAndScaleSet& info);
+ void RecordManipulationTypeCounts(const ScrollAndScaleSet& scroll_info);
void SendOverscrollAndScrollEndEventsFromImplSide(
const ScrollAndScaleSet& info);
void ApplyPageScaleDeltaFromImplSide(float page_scale_delta);
@@ -807,7 +804,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
gfx::ColorSpace raster_color_space_;
bool clear_caches_on_next_commit_ = false;
- uint32_t content_source_id_;
viz::LocalSurfaceIdAllocation local_surface_id_allocation_from_parent_;
// Used to detect surface invariant violations.
bool has_pushed_local_surface_id_from_parent_ = false;
@@ -882,7 +878,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// Used to vend weak pointers to LayerTreeHost to ScopedDeferMainFrameUpdate
// objects.
- base::WeakPtrFactory<LayerTreeHost> defer_main_frame_update_weak_ptr_factory_;
+ base::WeakPtrFactory<LayerTreeHost> defer_main_frame_update_weak_ptr_factory_{
+ this};
};
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h
index 5ddc975a950..f48af6c6d1e 100644
--- a/chromium/cc/trees/layer_tree_host_client.h
+++ b/chromium/cc/trees/layer_tree_host_client.h
@@ -53,6 +53,14 @@ struct ApplyViewportChangesArgs {
bool scroll_gesture_did_end;
};
+using ManipulationInfo = uint32_t;
+constexpr ManipulationInfo kManipulationInfoNone = 0;
+constexpr ManipulationInfo kManipulationInfoHasScrolledByWheel = 1 << 0;
+constexpr ManipulationInfo kManipulationInfoHasScrolledByTouch = 1 << 1;
+constexpr ManipulationInfo kManipulationInfoHasScrolledByPrecisionTouchPad =
+ 1 << 2;
+constexpr ManipulationInfo kManipulationInfoHasPinchZoomed = 1 << 3;
+
// A LayerTreeHost is bound to a LayerTreeHostClient. The main rendering
// loop (in ProxyMain or SingleThreadProxy) calls methods on the
// LayerTreeHost, which then handles them and also calls into the equivalent
@@ -104,9 +112,9 @@ class LayerTreeHostClient {
// related to pinch-zoom, browser controls (aka URL bar), overscroll, etc.
virtual void ApplyViewportChanges(const ApplyViewportChangesArgs& args) = 0;
- virtual void RecordWheelAndTouchScrollingCount(
- bool has_scrolled_by_wheel,
- bool has_scrolled_by_touch) = 0;
+ // Record use counts of different methods of scrolling (e.g. wheel, touch,
+ // precision touchpad, etc.).
+ virtual void RecordManipulationTypeCounts(ManipulationInfo info) = 0;
// Notifies the client when an overscroll has happened.
virtual void SendOverscrollEventFromImplSide(
diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc
index 6eb7ec07102..7ea7995ee11 100644
--- a/chromium/cc/trees/layer_tree_host_common.cc
+++ b/chromium/cc/trees/layer_tree_host_common.cc
@@ -81,7 +81,6 @@ LayerTreeHostCommon::CalcDrawPropsImplInputs::CalcDrawPropsImplInputs(
const gfx::Vector2dF& elastic_overscroll,
const ElementId elastic_overscroll_element_id,
int max_texture_size,
- bool can_adjust_raster_scales,
RenderSurfaceList* render_surface_list,
PropertyTrees* property_trees,
TransformNode* page_scale_transform_node)
@@ -96,7 +95,6 @@ LayerTreeHostCommon::CalcDrawPropsImplInputs::CalcDrawPropsImplInputs(
elastic_overscroll(elastic_overscroll),
elastic_overscroll_element_id(elastic_overscroll_element_id),
max_texture_size(max_texture_size),
- can_adjust_raster_scales(can_adjust_raster_scales),
render_surface_list(render_surface_list),
property_trees(property_trees),
page_scale_transform_node(page_scale_transform_node) {}
@@ -118,7 +116,6 @@ LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
gfx::Vector2dF(),
ElementId(),
std::numeric_limits<int>::max() / 2,
- false,
render_surface_list,
GetPropertyTrees(root_layer),
nullptr) {
@@ -181,9 +178,8 @@ ScrollAndScaleSet::ScrollAndScaleSet()
top_controls_delta(0.f),
browser_controls_constraint(BrowserControlsState::kBoth),
browser_controls_constraint_changed(false),
- has_scrolled_by_wheel(false),
- has_scrolled_by_touch(false),
- scroll_gesture_did_end(false) {}
+ scroll_gesture_did_end(false),
+ manipulation_info(kManipulationInfoNone) {}
ScrollAndScaleSet::~ScrollAndScaleSet() = default;
@@ -541,8 +537,7 @@ void CalculateDrawPropertiesInternal(
gfx::Rect(inputs->device_viewport_size), inputs->device_transform,
inputs->property_trees);
draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
- inputs->root_layer, inputs->property_trees,
- inputs->can_adjust_raster_scales);
+ inputs->root_layer, inputs->property_trees);
// Property trees are normally constructed on the main thread and
// passed to compositor thread. Source to parent updates on them are not
@@ -609,8 +604,7 @@ void CalculateDrawPropertiesInternal(
inputs->device_scale_factor, page_scale_factor_for_root,
inputs->device_transform);
draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
- inputs->root_layer, inputs->property_trees,
- inputs->can_adjust_raster_scales);
+ inputs->root_layer, inputs->property_trees);
break;
}
}
diff --git a/chromium/cc/trees/layer_tree_host_common.h b/chromium/cc/trees/layer_tree_host_common.h
index c27157a9939..07c0bc586c2 100644
--- a/chromium/cc/trees/layer_tree_host_common.h
+++ b/chromium/cc/trees/layer_tree_host_common.h
@@ -74,7 +74,6 @@ class CC_EXPORT LayerTreeHostCommon {
const gfx::Vector2dF& elastic_overscroll,
const ElementId elastic_overscroll_element_id,
int max_texture_size,
- bool can_adjust_raster_scales,
RenderSurfaceList* render_surface_list,
PropertyTrees* property_trees,
TransformNode* page_scale_transform_node);
@@ -90,7 +89,6 @@ class CC_EXPORT LayerTreeHostCommon {
gfx::Vector2dF elastic_overscroll;
const ElementId elastic_overscroll_element_id;
int max_texture_size;
- bool can_adjust_raster_scales;
RenderSurfaceList* render_surface_list;
PropertyTrees* property_trees;
TransformNode* page_scale_transform_node;
@@ -189,12 +187,14 @@ struct CC_EXPORT ScrollAndScaleSet {
std::vector<std::unique_ptr<SwapPromise>> swap_promises;
BrowserControlsState browser_controls_constraint;
bool browser_controls_constraint_changed;
- bool has_scrolled_by_wheel;
- bool has_scrolled_by_touch;
// Set to true when a scroll gesture being handled on the compositor has
// ended.
bool scroll_gesture_did_end;
+
+ // Tracks different methods of scrolling (e.g. wheel, touch, precision
+ // touchpad, etc.).
+ ManipulationInfo manipulation_info;
};
template <typename Function>
diff --git a/chromium/cc/trees/layer_tree_host_common_perftest.cc b/chromium/cc/trees/layer_tree_host_common_perftest.cc
index 2c1c4ab1d82..4cb8bc9e760 100644
--- a/chromium/cc/trees/layer_tree_host_common_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_perftest.cc
@@ -107,7 +107,6 @@ class CalcDrawPropsTest : public LayerTreeHostCommonPerfTest {
active_tree->OuterViewportScrollLayer(),
active_tree->elastic_overscroll()->Current(active_tree->IsActiveTree()),
active_tree->OverscrollElasticityElementId(), max_texture_size,
- host_impl->settings().layer_transforms_should_scale_layer_contents,
&update_list, active_tree->property_trees(),
active_tree->property_trees()->transform_tree.Node(
active_tree->InnerViewportContainerLayer()
diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc
index 93750755adb..12652e57e9f 100644
--- a/chromium/cc/trees/layer_tree_host_common_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc
@@ -168,7 +168,6 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
inputs.page_scale_layer = page_scale_layer;
inputs.inner_viewport_scroll_layer = inner_viewport_scroll_layer;
inputs.outer_viewport_scroll_layer = outer_viewport_scroll_layer;
- inputs.can_adjust_raster_scales = true;
if (page_scale_layer) {
PropertyTrees* property_trees =
root_layer->layer_tree_impl()->property_trees();
@@ -236,7 +235,6 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
void ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(
LayerImpl* root_layer) {
DCHECK(root_layer->layer_tree_impl());
- bool can_adjust_raster_scales = true;
const LayerImpl* page_scale_layer = nullptr;
LayerImpl* inner_viewport_scroll_layer =
@@ -262,8 +260,8 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
outer_viewport_scroll_layer, overscroll_elasticity_element_id,
elastic_overscroll, page_scale_factor, device_scale_factor,
gfx::Rect(device_viewport_size), gfx::Transform(), property_trees);
- draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
- root_layer, property_trees, can_adjust_raster_scales);
+ draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(root_layer,
+ property_trees);
draw_property_utils::FindLayersThatNeedUpdates(
root_layer->layer_tree_impl(), property_trees,
update_layer_impl_list_.get());
@@ -280,7 +278,6 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
DCHECK(!root_layer->bounds().IsEmpty());
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root_layer, device_viewport_size, render_surface_list_impl_.get());
- inputs.can_adjust_raster_scales = false;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
}
@@ -311,7 +308,7 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
bool VerifyLayerInList(scoped_refptr<Layer> layer,
const LayerList* layer_list) {
- return base::ContainsValue(*layer_list, layer);
+ return base::Contains(*layer_list, layer);
}
private:
@@ -323,18 +320,11 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
class LayerTreeHostCommonTest : public LayerTreeHostCommonTestBase,
public testing::Test {};
-class LayerTreeSettingsScaleContent : public VerifyTreeCalcsLayerTreeSettings {
- public:
- LayerTreeSettingsScaleContent() {
- layer_transforms_should_scale_layer_contents = true;
- }
-};
-
class LayerTreeHostCommonScalingTest : public LayerTreeHostCommonTestBase,
public testing::Test {
public:
LayerTreeHostCommonScalingTest()
- : LayerTreeHostCommonTestBase(LayerTreeSettingsScaleContent()) {}
+ : LayerTreeHostCommonTestBase(VerifyTreeCalcsLayerTreeSettings()) {}
};
class LayerTreeHostCommonDrawRectsTest : public LayerTreeHostCommonTest {
@@ -1401,7 +1391,6 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) {
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root, root->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// Since the layer is transparent, render_surface1->GetRenderSurface() should
@@ -1437,7 +1426,6 @@ TEST_F(LayerTreeHostCommonTest,
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root, root->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
EXPECT_EQ(2U, render_surface_list.size());
}
@@ -1461,7 +1449,6 @@ TEST_F(LayerTreeHostCommonTest,
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root, root->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
}
@@ -1496,7 +1483,6 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForFilter) {
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root, root->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
ASSERT_TRUE(GetRenderSurface(parent));
@@ -4436,7 +4422,6 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root_layer, root_layer->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// We should have one render surface and two layers. The child
@@ -4451,7 +4436,6 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
RenderSurfaceList render_surface_list2;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs2(
root_layer, root_layer->bounds(), &render_surface_list2);
- inputs2.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs2);
LayerImpl* child_ptr = root_layer->layer_tree_impl()->LayerById(2);
@@ -4468,7 +4452,6 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
RenderSurfaceList render_surface_list3;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs3(
root_layer, root_layer->bounds(), &render_surface_list3);
- inputs3.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs3);
child_ptr = root_layer->layer_tree_impl()->LayerById(2);
@@ -4754,7 +4737,6 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) {
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root_layer, root_layer->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// We should have one render surface and two layers. The grand child has
@@ -4798,7 +4780,6 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayersImpl) {
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root_layer, root_layer->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// We should have one render surface and one layer. The child has
@@ -4894,7 +4875,6 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root_layer, root_layer->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
auto& effect_tree =
@@ -5002,7 +4982,6 @@ TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) {
root_layer->layer_tree_impl()->SetRootLayerForTesting(std::move(root));
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root_layer, root_layer->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// We should have two render surface, as the others are clipped out.
@@ -6442,7 +6421,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionSubpixelScroll) {
sticky_position.is_sticky = true;
sticky_position.is_anchored_bottom = true;
sticky_position.bottom_offset = 10.0f;
- sticky_position.constraint_box_rect = gfx::RectF(0, 0, 100, 100);
+ sticky_position.constraint_box_rect = gfx::Rect(0, 0, 100, 100);
sticky_position.scroll_container_relative_sticky_box_rect =
gfx::Rect(0, 200, 10, 10);
sticky_position.scroll_container_relative_containing_block_rect =
@@ -6489,7 +6468,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottom) {
sticky_position.is_sticky = true;
sticky_position.is_anchored_bottom = true;
sticky_position.bottom_offset = 10.0f;
- sticky_position.constraint_box_rect = gfx::RectF(0, 0, 100, 100);
+ sticky_position.constraint_box_rect = gfx::Rect(0, 0, 100, 100);
sticky_position.scroll_container_relative_sticky_box_rect =
gfx::Rect(0, 150, 10, 10);
sticky_position.scroll_container_relative_containing_block_rect =
@@ -6571,7 +6550,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottomOuterViewportDelta) {
sticky_position.is_sticky = true;
sticky_position.is_anchored_bottom = true;
sticky_position.bottom_offset = 10.0f;
- sticky_position.constraint_box_rect = gfx::RectF(0, 0, 100, 100);
+ sticky_position.constraint_box_rect = gfx::Rect(0, 0, 100, 100);
sticky_position.scroll_container_relative_sticky_box_rect =
gfx::Rect(0, 70, 10, 10);
sticky_position.scroll_container_relative_containing_block_rect =
@@ -6650,7 +6629,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionLeftRight) {
sticky_position.is_anchored_right = true;
sticky_position.left_offset = 10.f;
sticky_position.right_offset = 10.f;
- sticky_position.constraint_box_rect = gfx::RectF(0, 0, 100, 100);
+ sticky_position.constraint_box_rect = gfx::Rect(0, 0, 100, 100);
sticky_position.scroll_container_relative_sticky_box_rect =
gfx::Rect(145, 0, 10, 10);
sticky_position.scroll_container_relative_containing_block_rect =
@@ -7303,7 +7282,6 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) {
FakeImplTaskRunnerProvider task_runner_provider;
TestTaskGraphRunner task_graph_runner;
LayerTreeSettings settings = host()->GetSettings();
- settings.layer_transforms_should_scale_layer_contents = true;
FakeLayerTreeHostImpl host_impl(settings, &task_runner_provider,
&task_graph_runner);
std::unique_ptr<AnimationScaleFactorTrackingLayerImpl> grand_parent =
@@ -7790,7 +7768,6 @@ TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
FakeImplTaskRunnerProvider task_runner_provider;
TestTaskGraphRunner task_graph_runner;
LayerTreeSettings settings = host()->GetSettings();
- settings.layer_transforms_should_scale_layer_contents = true;
FakeLayerTreeHostImpl host_impl(settings, &task_runner_provider,
&task_graph_runner);
@@ -7864,7 +7841,6 @@ TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
root_layer, device_viewport_size, &render_surface_list);
inputs.page_scale_factor = page_scale_factor;
- inputs.can_adjust_raster_scales = true;
inputs.page_scale_layer = root_layer;
inputs.page_scale_transform_node = inputs.property_trees->transform_tree.Node(
inputs.page_scale_layer->transform_tree_index());
@@ -7886,7 +7862,6 @@ TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
device_scale_factor = 4.0f;
inputs.device_scale_factor = device_scale_factor;
- inputs.can_adjust_raster_scales = true;
root_layer->layer_tree_impl()->property_trees()->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
@@ -7906,7 +7881,6 @@ TEST_F(LayerTreeHostCommonTest, AnimationScales) {
FakeImplTaskRunnerProvider task_runner_provider;
TestTaskGraphRunner task_graph_runner;
LayerTreeSettings settings = host()->GetSettings();
- settings.layer_transforms_should_scale_layer_contents = true;
FakeLayerTreeHostImpl host_impl(settings, &task_runner_provider,
&task_graph_runner);
@@ -7974,56 +7948,6 @@ TEST_F(LayerTreeHostCommonTest, AnimationScales) {
EXPECT_FLOAT_EQ(100.f, GetStartingAnimationScale(child2_layer));
}
-TEST_F(LayerTreeHostCommonTest,
- AnimationScaleWhenLayerTransformShouldNotScaleLayerBounds) {
- // Returns empty scale if layer_transforms_should_scale_layer_contents is
- // false.
- FakeImplTaskRunnerProvider task_runner_provider;
- TestTaskGraphRunner task_graph_runner;
- LayerTreeSettings settings = host()->GetSettings();
- settings.layer_transforms_should_scale_layer_contents = false;
- FakeLayerTreeHostImpl host_impl(settings, &task_runner_provider,
- &task_graph_runner);
-
- std::unique_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 1);
- LayerImpl* root_layer = root.get();
- std::unique_ptr<LayerImpl> child =
- LayerImpl::Create(host_impl.active_tree(), 2);
- LayerImpl* child_layer = child.get();
-
- root->test_properties()->AddChild(std::move(child));
- host_impl.active_tree()->SetRootLayerForTesting(std::move(root));
-
- host_impl.active_tree()->SetElementIdsForTesting();
-
- gfx::Transform scale_transform_child;
- scale_transform_child.Scale(4, 5);
-
- root_layer->SetBounds(gfx::Size(1, 1));
- child_layer->test_properties()->transform = scale_transform_child;
- child_layer->SetBounds(gfx::Size(1, 1));
-
- TransformOperations scale;
- scale.AppendScale(5.f, 8.f, 3.f);
-
- scoped_refptr<AnimationTimeline> timeline =
- AnimationTimeline::Create(AnimationIdProvider::NextTimelineId());
- host_impl.animation_host()->AddAnimationTimeline(timeline);
-
- AddAnimatedTransformToElementWithAnimation(
- child_layer->element_id(), timeline, 1.0, TransformOperations(), scale);
-
- root_layer->layer_tree_impl()->property_trees()->needs_rebuild = true;
- ExecuteCalculateDrawProperties(root_layer);
-
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(root_layer));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(child_layer));
-
- EXPECT_FLOAT_EQ(kNotScaled, GetStartingAnimationScale(root_layer));
- EXPECT_FLOAT_EQ(kNotScaled, GetStartingAnimationScale(child_layer));
-}
-
TEST_F(LayerTreeHostCommonTest, VisibleContentRectInChildRenderSurface) {
LayerImpl* root = root_layer_for_testing();
LayerImpl* clip = AddChild<LayerImpl>(root);
@@ -9789,7 +9713,7 @@ TEST_F(LayerTreeHostCommonTest, LargeTransformTest) {
// The root layer should be in the RenderSurfaceList.
const auto* rsl = render_surface_list_impl();
- EXPECT_TRUE(base::ContainsValue(*rsl, GetRenderSurface(root)));
+ EXPECT_TRUE(base::Contains(*rsl, GetRenderSurface(root)));
}
TEST_F(LayerTreeHostCommonTest, PropertyTreesRebuildWithOpacityChanges) {
@@ -10143,40 +10067,7 @@ TEST_F(LayerTreeHostCommonTest, ScrollTreeBuilderTest) {
EXPECT_EQ(scroll_root1.id, grand_child12->scroll_tree_index());
}
-TEST_F(LayerTreeHostCommonTest, CanAdjustRasterScaleTest) {
- LayerImpl* root = root_layer_for_testing();
- LayerImpl* render_surface = AddChild<LayerImpl>(root);
- LayerImpl* child = AddChild<LayerImpl>(render_surface);
-
- root->SetBounds(gfx::Size(50, 50));
-
- render_surface->SetBounds(gfx::Size(10, 10));
- render_surface->test_properties()->force_render_surface = true;
- gfx::Transform transform;
- transform.Scale(5.f, 5.f);
- render_surface->test_properties()->transform = transform;
-
- child->SetDrawsContent(true);
- child->SetMasksToBounds(true);
- child->SetBounds(gfx::Size(10, 10));
-
- ExecuteCalculateDrawPropertiesWithoutAdjustingRasterScales(root);
-
- // Check surface draw properties.
- EXPECT_EQ(gfx::Rect(10, 10),
- GetRenderSurface(render_surface)->content_rect());
- EXPECT_EQ(transform, GetRenderSurface(render_surface)->draw_transform());
- EXPECT_EQ(gfx::RectF(50.0f, 50.0f),
- GetRenderSurface(render_surface)->DrawableContentRect());
-
- // Check child layer draw properties.
- EXPECT_EQ(gfx::Rect(10, 10), child->visible_layer_rect());
- EXPECT_EQ(gfx::Transform(), child->DrawTransform());
- EXPECT_EQ(gfx::Rect(10, 10), child->clip_rect());
- EXPECT_EQ(gfx::Rect(10, 10), child->drawable_content_rect());
-}
-
-TEST_F(LayerTreeHostCommonTest, SurfaceContentsScaleChangeWithCopyRequestTest) {
+TEST_F(LayerTreeHostCommonTest, CopyRequestScalingTest) {
LayerImpl* root = root_layer_for_testing();
LayerImpl* scale_layer = AddChild<LayerImpl>(root);
LayerImpl* copy_layer = AddChild<LayerImpl>(scale_layer);
@@ -10203,7 +10094,7 @@ TEST_F(LayerTreeHostCommonTest, SurfaceContentsScaleChangeWithCopyRequestTest) {
test_layer->SetMasksToBounds(true);
test_layer->SetBounds(gfx::Size(20, 20));
- ExecuteCalculateDrawPropertiesWithoutAdjustingRasterScales(root);
+ ExecuteCalculateDrawProperties(root);
// Check surface with copy request draw properties.
EXPECT_EQ(gfx::Rect(50, 50), GetRenderSurface(copy_layer)->content_rect());
@@ -10219,19 +10110,7 @@ TEST_F(LayerTreeHostCommonTest, SurfaceContentsScaleChangeWithCopyRequestTest) {
// Clear the copy request and call UpdateSurfaceContentsScale.
host_impl()->active_tree()->property_trees()->effect_tree.ClearCopyRequests();
- ExecuteCalculateDrawPropertiesWithoutAdjustingRasterScales(root);
-
- // Check surface draw properties without copy request.
- EXPECT_EQ(gfx::Rect(10, 10), GetRenderSurface(copy_layer)->content_rect());
- EXPECT_EQ(transform, GetRenderSurface(copy_layer)->draw_transform());
- EXPECT_EQ(gfx::RectF(50.0f, 50.0f),
- GetRenderSurface(copy_layer)->DrawableContentRect());
-
- // Check test layer draw properties without copy request.
- EXPECT_EQ(gfx::Rect(10, 10), test_layer->visible_layer_rect());
- EXPECT_EQ(gfx::Transform(), test_layer->DrawTransform());
- EXPECT_EQ(gfx::Rect(10, 10), test_layer->clip_rect());
- EXPECT_EQ(gfx::Rect(10, 10), test_layer->drawable_content_rect());
+ ExecuteCalculateDrawProperties(root);
}
TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCacheRenderSurface) {
@@ -10316,7 +10195,6 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCacheRenderSurface) {
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root_layer, root_layer->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// We should have four render surfaces, one for the root, one for the grand
@@ -10541,7 +10419,6 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTrilinearFiltering) {
RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root, root->bounds(), &render_surface_list);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
ASSERT_TRUE(GetRenderSurface(parent));
@@ -11677,5 +11554,229 @@ TEST_F(LayerTreeHostCommonTest,
kRoundedCorner4Radius * kDeviceScale);
}
+TEST_F(LayerTreeHostCommonTest, CustomLayerClipBounds) {
+ // The custom clip API should have the same effect as if an intermediate
+ // clip layer has been added to the layer tree. To check this the test creates
+ // 2 subtree for a root layer. One of the subtree uses the clip API to clip
+ // its subtree while the other uses an intermediate layer. The resulting clip
+ // in draw properties are expected to be the same.
+ // -Root
+ // - Parent [Clip set to |kClipBounds| using API]
+ // - Child
+ // - Clip Layer [Masks to bounds = true] [Layer bounds set to |kClipBounds|]
+ // - Expected Parent
+ // - Expected Child
+ constexpr float kDeviceScale = 1.f;
+
+ const gfx::Rect kRootLayerBounds(0, 0, 100, 100);
+ const gfx::Rect kParentLayerBounds(0, 0, 50, 100);
+ const gfx::Rect kChildLayerBounds(20, 20, 30, 60);
+
+ constexpr gfx::Rect kClipBounds(10, 10, 50, 50);
+
+ // The position of |Expected Parent| on screen should be same as |Parent|.
+ const gfx::Rect kExpectedParentLayerBounds(
+ gfx::Point(0, 0) - kClipBounds.OffsetFromOrigin(), gfx::Size(50, 100));
+
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> parent = Layer::Create();
+ scoped_refptr<Layer> child = Layer::Create();
+
+ scoped_refptr<Layer> clip_layer = Layer::Create();
+ scoped_refptr<Layer> expected_parent = Layer::Create();
+ scoped_refptr<Layer> expected_child = Layer::Create();
+
+ root->AddChild(parent);
+ parent->AddChild(child);
+
+ root->AddChild(clip_layer);
+ clip_layer->AddChild(expected_parent);
+ expected_parent->AddChild(expected_child);
+
+ host()->SetRootLayer(root);
+
+ root->SetIsDrawable(true);
+ parent->SetIsDrawable(true);
+ child->SetIsDrawable(true);
+ expected_parent->SetIsDrawable(true);
+ expected_child->SetIsDrawable(true);
+
+ // Set layer positions.
+ root->SetPosition(gfx::PointF(kRootLayerBounds.origin()));
+ parent->SetPosition(gfx::PointF(kParentLayerBounds.origin()));
+ child->SetPosition(gfx::PointF(kChildLayerBounds.origin()));
+
+ clip_layer->SetPosition(gfx::PointF(kClipBounds.origin()));
+ expected_parent->SetPosition(
+ gfx::PointF(kExpectedParentLayerBounds.origin()));
+ expected_child->SetPosition(gfx::PointF(kChildLayerBounds.origin()));
+
+ root->SetBounds(kRootLayerBounds.size());
+ parent->SetBounds(kParentLayerBounds.size());
+ child->SetBounds(kChildLayerBounds.size());
+
+ clip_layer->SetBounds(kClipBounds.size());
+ expected_parent->SetBounds(kExpectedParentLayerBounds.size());
+ expected_child->SetBounds(kChildLayerBounds.size());
+
+ parent->SetClipRect(kClipBounds);
+ clip_layer->SetMasksToBounds(true);
+
+ ExecuteCalculateDrawProperties(root.get(), kDeviceScale);
+
+ const ClipTree& clip_tree =
+ root->layer_tree_host()->property_trees()->clip_tree;
+
+ const ClipNode* parent_clip_node = clip_tree.Node(parent->clip_tree_index());
+ EXPECT_EQ(parent_clip_node->clip, gfx::RectF(kClipBounds));
+ EXPECT_TRUE(!parent->clip_rect().IsEmpty());
+
+ const ClipNode* child_clip_node = clip_tree.Node(child->clip_tree_index());
+ EXPECT_EQ(child_clip_node->clip, gfx::RectF(kClipBounds));
+
+ host()->host_impl()->CreatePendingTree();
+ host()->CommitAndCreatePendingTree();
+ // TODO(https://crbug.com/939968) This call should be handled by
+ // FakeLayerTreeHost instead of manually pushing the properties from the
+ // layer tree host to the pending tree.
+ root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree());
+ host()->host_impl()->ActivateSyncTree();
+ LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree();
+
+ // Get the layer impl for each Layer.
+ LayerImpl* root_impl = layer_tree_impl->LayerById(root->id());
+ LayerImpl* parent_impl = layer_tree_impl->LayerById(parent->id());
+ LayerImpl* child_impl = layer_tree_impl->LayerById(child->id());
+ LayerImpl* expected_parent_impl =
+ layer_tree_impl->LayerById(expected_parent->id());
+ LayerImpl* expected_child_impl =
+ layer_tree_impl->LayerById(expected_child->id());
+
+ ExecuteCalculateDrawProperties(root_impl, kDeviceScale);
+
+ EXPECT_TRUE(parent_impl->is_clipped());
+ EXPECT_TRUE(child_impl->is_clipped());
+ ASSERT_TRUE(expected_parent_impl->is_clipped());
+ ASSERT_TRUE(expected_child_impl->is_clipped());
+
+ EXPECT_EQ(parent_impl->clip_rect(), expected_parent_impl->clip_rect());
+ EXPECT_EQ(child_impl->clip_rect(), expected_child_impl->clip_rect());
+}
+
+TEST_F(LayerTreeHostCommonTest, CustomLayerClipBoundsWithMaskToBounds) {
+ // The custom clip API should have the same effect as if an intermediate
+ // clip layer has been added to the layer tree. To check this the test creates
+ // 2 subtree for a root layer. One of the subtree uses the clip API to clip
+ // its subtree while the other uses an intermediate layer. The resulting clip
+ // in draw properties are expected to be the same. In this test, the subtree
+ // roots also have their masks to bounds property set.
+ // -Root
+ // - Parent [Clip set to |kClipBounds| using API]
+ // - Child
+ // - Clip Layer [Masks to bounds = true] [Layer bounds set to |kClipBounds|]
+ // - Expected Parent [Masks to bounds = true]
+ // - Expected Child
+ constexpr float kDeviceScale = 1.f;
+
+ const gfx::Rect kRootLayerBounds(0, 0, 100, 100);
+ const gfx::Rect kParentLayerBounds(0, 0, 50, 100);
+ const gfx::Rect kChildLayerBounds(20, 20, 30, 60);
+
+ constexpr gfx::Rect kClipBounds(10, 10, 50, 50);
+
+ // The position of |Expected Parent| on screen should be same as |Parent|.
+ const gfx::Rect kExpectedParentLayerBounds(
+ gfx::Point(0, 0) - kClipBounds.OffsetFromOrigin(), gfx::Size(50, 100));
+
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> parent = Layer::Create();
+ scoped_refptr<Layer> child = Layer::Create();
+
+ scoped_refptr<Layer> clip_layer = Layer::Create();
+ scoped_refptr<Layer> expected_parent = Layer::Create();
+ scoped_refptr<Layer> expected_child = Layer::Create();
+
+ root->AddChild(parent);
+ parent->AddChild(child);
+
+ root->AddChild(clip_layer);
+ clip_layer->AddChild(expected_parent);
+ expected_parent->AddChild(expected_child);
+
+ host()->SetRootLayer(root);
+
+ root->SetIsDrawable(true);
+ parent->SetIsDrawable(true);
+ child->SetIsDrawable(true);
+ expected_parent->SetIsDrawable(true);
+ expected_child->SetIsDrawable(true);
+
+ // Set layer positions.
+ root->SetPosition(gfx::PointF(kRootLayerBounds.origin()));
+ parent->SetPosition(gfx::PointF(kParentLayerBounds.origin()));
+ child->SetPosition(gfx::PointF(kChildLayerBounds.origin()));
+
+ clip_layer->SetPosition(gfx::PointF(kClipBounds.origin()));
+ expected_parent->SetPosition(
+ gfx::PointF(kExpectedParentLayerBounds.origin()));
+ expected_child->SetPosition(gfx::PointF(kChildLayerBounds.origin()));
+
+ root->SetBounds(kRootLayerBounds.size());
+ parent->SetBounds(kParentLayerBounds.size());
+ child->SetBounds(kChildLayerBounds.size());
+
+ clip_layer->SetBounds(kClipBounds.size());
+ expected_parent->SetBounds(kExpectedParentLayerBounds.size());
+ expected_child->SetBounds(kChildLayerBounds.size());
+
+ parent->SetClipRect(kClipBounds);
+ parent->SetMasksToBounds(true);
+
+ clip_layer->SetMasksToBounds(true);
+ expected_parent->SetMasksToBounds(true);
+
+ ExecuteCalculateDrawProperties(root.get(), kDeviceScale);
+
+ const ClipTree& clip_tree =
+ root->layer_tree_host()->property_trees()->clip_tree;
+
+ const ClipNode* parent_clip_node = clip_tree.Node(parent->clip_tree_index());
+ const gfx::RectF expected_clip_bounds = gfx::IntersectRects(
+ gfx::RectF(kClipBounds), gfx::RectF(kParentLayerBounds));
+ EXPECT_EQ(parent_clip_node->clip, expected_clip_bounds);
+ EXPECT_TRUE(!parent->clip_rect().IsEmpty());
+
+ const ClipNode* child_clip_node = clip_tree.Node(child->clip_tree_index());
+ EXPECT_EQ(child_clip_node->clip, expected_clip_bounds);
+
+ host()->host_impl()->CreatePendingTree();
+ host()->CommitAndCreatePendingTree();
+ // TODO(https://crbug.com/939968) This call should be handled by
+ // FakeLayerTreeHost instead of manually pushing the properties from the
+ // layer tree host to the pending tree.
+ root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree());
+ host()->host_impl()->ActivateSyncTree();
+ LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree();
+
+ // Get the layer impl for each Layer.
+ LayerImpl* root_impl = layer_tree_impl->LayerById(root->id());
+ LayerImpl* parent_impl = layer_tree_impl->LayerById(parent->id());
+ LayerImpl* child_impl = layer_tree_impl->LayerById(child->id());
+ LayerImpl* expected_parent_impl =
+ layer_tree_impl->LayerById(expected_parent->id());
+ LayerImpl* expected_child_impl =
+ layer_tree_impl->LayerById(expected_child->id());
+
+ ExecuteCalculateDrawProperties(root_impl, kDeviceScale);
+
+ EXPECT_TRUE(parent_impl->is_clipped());
+ EXPECT_TRUE(child_impl->is_clipped());
+ ASSERT_TRUE(expected_parent_impl->is_clipped());
+ ASSERT_TRUE(expected_child_impl->is_clipped());
+
+ EXPECT_EQ(parent_impl->clip_rect(), expected_parent_impl->clip_rect());
+ EXPECT_EQ(child_impl->clip_rect(), expected_child_impl->clip_rect());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index e2921219d25..0585a41551c 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -38,6 +38,7 @@
#include "cc/input/page_scale_animation.h"
#include "cc/input/scroll_elasticity_helper.h"
#include "cc/input/scroll_state.h"
+#include "cc/input/scrollbar.h"
#include "cc/input/scrollbar_animation_controller.h"
#include "cc/input/scroller_size_metrics.h"
#include "cc/input/snap_selection_strategy.h"
@@ -323,7 +324,8 @@ LayerTreeHostImpl::LayerTreeHostImpl(
task_runner_provider_(task_runner_provider),
current_begin_frame_tracker_(BEGINFRAMETRACKER_FROM_HERE),
compositor_frame_reporting_controller_(
- std::make_unique<CompositorFrameReportingController>()),
+ std::make_unique<CompositorFrameReportingController>(
+ settings.single_thread_proxy_scheduler)),
settings_(settings),
is_synchronous_single_threaded_(!task_runner_provider->HasImplThread() &&
!settings_.single_thread_proxy_scheduler),
@@ -358,8 +360,7 @@ LayerTreeHostImpl::LayerTreeHostImpl(
is_animating_for_snap_(false),
paint_image_generator_client_id_(PaintImage::GetNextGeneratorClientId()),
scrollbar_controller_(std::make_unique<ScrollbarController>(this)),
- scroll_gesture_did_end_(false),
- weak_factory_(this) {
+ scroll_gesture_did_end_(false) {
DCHECK(mutator_host_);
mutator_host_->SetMutatorHostClient(this);
@@ -427,9 +428,21 @@ LayerTreeHostImpl::~LayerTreeHostImpl() {
mutator_host_->SetMutatorHostClient(nullptr);
}
+void LayerTreeHostImpl::DidSendBeginMainFrame(const viz::BeginFrameArgs& args) {
+ if (impl_thread_phase_ == ImplThreadPhase::INSIDE_IMPL_FRAME)
+ begin_main_frame_sent_during_impl_ = true;
+ frame_trackers_.NotifyBeginMainFrame(args);
+}
+
void LayerTreeHostImpl::BeginMainFrameAborted(
CommitEarlyOutReason reason,
- std::vector<std::unique_ptr<SwapPromise>> swap_promises) {
+ std::vector<std::unique_ptr<SwapPromise>> swap_promises,
+ const viz::BeginFrameArgs& args) {
+ if (reason == CommitEarlyOutReason::ABORTED_NOT_VISIBLE ||
+ reason == CommitEarlyOutReason::FINISHED_NO_UPDATES) {
+ frame_trackers_.NotifyMainFrameCausedNoDamage(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.
@@ -457,7 +470,7 @@ void LayerTreeHostImpl::CommitComplete() {
// In high latency mode commit cannot finish within the same frame. We need to
// flush input here to make sure they got picked up by |PrepareTiles()|.
if (input_handler_client_ && impl_thread_phase_ == ImplThreadPhase::IDLE)
- input_handler_client_->DeliverInputForBeginFrame();
+ input_handler_client_->DeliverInputForHighLatencyMode();
if (CommitToActiveTree()) {
active_tree_->HandleScrollbarShowRequestsFromMain();
@@ -483,6 +496,18 @@ void LayerTreeHostImpl::CommitComplete() {
UpdateSyncTreeAfterCommitOrImplSideInvalidation();
micro_benchmark_controller_.DidCompleteCommit();
+
+ if (mutator_host_->CurrentFrameHadRAF() &&
+ !request_animation_frame_tracker_) {
+ request_animation_frame_tracker_ =
+ frame_trackers_.CreateTracker(FrameSequenceTrackerType::kRAF);
+ }
+
+ if (mutator_host_->MainThreadAnimationsCount() > 0 &&
+ !main_thread_animation_frame_tracker_) {
+ main_thread_animation_frame_tracker_ = frame_trackers_.CreateTracker(
+ FrameSequenceTrackerType::kMainThreadAnimation);
+ }
}
void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
@@ -529,6 +554,97 @@ void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
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;
+ }
+
+ PaintWorkletJobMap dirty_paint_worklets = GatherDirtyPaintWorklets();
+ 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() const {
+ PaintWorkletJobMap dirty_paint_worklets;
+ for (PictureLayerImpl* layer :
+ sync_tree()->picture_layers_with_paint_worklets()) {
+ for (const auto& entry : layer->GetPaintWorkletRecordMap()) {
+ // If we already have a record we can reuse it and so the
+ // PaintWorkletInput isn't dirty.
+ if (entry.second)
+ continue;
+
+ int id = entry.first->WorkletId();
+ auto result = dirty_paint_worklets.insert(
+ std::make_pair(id, scoped_refptr<PaintWorkletJobVector>{}));
+ scoped_refptr<PaintWorkletJobVector>& job_vector = result.first->second;
+ if (!job_vector)
+ job_vector = base::WrapRefCounted(new PaintWorkletJobVector);
+ job_vector->data.emplace_back(layer->id(), entry.first);
+ }
+ }
+ return dirty_paint_worklets;
+}
+
+void LayerTreeHostImpl::OnPaintWorkletResultsReady(PaintWorkletJobMap results) {
+ // 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.
+ DCHECK_EQ(results.size(), GatherDirtyPaintWorklets().size());
+
+ 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.
@@ -714,8 +830,7 @@ bool LayerTreeHostImpl::IsCurrentlyScrollingViewport() const {
}
bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt(
- const gfx::Point& viewport_point,
- InputHandler::ScrollInputType type) const {
+ const gfx::Point& viewport_point) const {
auto* scrolling_node = CurrentlyScrollingNode();
if (!scrolling_node)
return false;
@@ -729,7 +844,7 @@ bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt(
bool scroll_on_main_thread = false;
uint32_t main_thread_scrolling_reasons;
auto* test_scroll_node = FindScrollNodeForDeviceViewportPoint(
- device_viewport_point, type, layer_impl, &scroll_on_main_thread,
+ device_viewport_point, layer_impl, &scroll_on_main_thread,
&main_thread_scrolling_reasons);
if (scroll_on_main_thread)
@@ -1183,6 +1298,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
}
frame->use_default_lower_bound_deadline |=
append_quads_data.use_default_lower_bound_deadline;
+ frame->mirror_rect.Union(append_quads_data.mirror_rect);
}
// If CommitToActiveTree() is true, then we wait to draw until
@@ -1338,10 +1454,19 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
if (client_name) {
size_t total_memory_in_bytes = 0;
size_t total_gpu_memory_for_tilings_in_bytes = 0;
+ int layers_with_text_count = 0;
+ int layers_with_text_no_lcd_text_count = 0;
for (const PictureLayerImpl* layer : active_tree()->picture_layers()) {
total_memory_in_bytes += layer->GetRasterSource()->GetMemoryUsage();
total_gpu_memory_for_tilings_in_bytes += layer->GPUMemoryUsageInBytes();
+ if (layer->GetRasterSource()->HasText()) {
+ layers_with_text_count++;
+ if (!layer->can_use_lcd_text()) {
+ layers_with_text_no_lcd_text_count++;
+ }
+ }
}
+
if (total_memory_in_bytes != 0) {
UMA_HISTOGRAM_COUNTS_1M(
base::StringPrintf("Compositing.%s.PictureMemoryUsageKb",
@@ -1359,6 +1484,34 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
base::saturated_cast<int>(active_tree_->picture_layers().size()), 1,
400, 20);
+ if (layers_with_text_count > 0) {
+ int percent =
+ 100.0 * layers_with_text_no_lcd_text_count / layers_with_text_count;
+
+ if (layers_with_text_count < 10) {
+ UMA_HISTOGRAM_PERCENTAGE(
+ base::StringPrintf(
+ "Compositing.%s.PercentPictureLayersWithTextButLCDTextDisabled."
+ "LessThan10",
+ client_name),
+ percent);
+ } else if (layers_with_text_count <= 30) {
+ UMA_HISTOGRAM_PERCENTAGE(
+ base::StringPrintf(
+ "Compositing.%s.PercentPictureLayersWithTextButLCDTextDisabled."
+ "10To30",
+ client_name),
+ percent);
+ } else {
+ UMA_HISTOGRAM_PERCENTAGE(
+ base::StringPrintf(
+ "Compositing.%s."
+ "PercentPictureLayersWithTextButLCDTextDisabled.MoreThan30",
+ client_name),
+ percent);
+ }
+ }
+
// TODO(yigu): Maybe we should use the same check above. Need to figure out
// why exactly we skip 0.
if (!active_tree()->picture_layers().empty()) {
@@ -1588,11 +1741,12 @@ std::unique_ptr<RasterTilePriorityQueue> LayerTreeHostImpl::BuildRasterQueue(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"LayerTreeHostImpl::BuildRasterQueue");
- return RasterTilePriorityQueue::Create(active_tree_->picture_layers(),
- pending_tree_
- ? pending_tree_->picture_layers()
- : std::vector<PictureLayerImpl*>(),
- tree_priority, type);
+ return RasterTilePriorityQueue::Create(
+ active_tree_->picture_layers(),
+ pending_tree_ && pending_tree_fully_painted_
+ ? pending_tree_->picture_layers()
+ : std::vector<PictureLayerImpl*>(),
+ tree_priority, type);
}
std::unique_ptr<EvictionTilePriorityQueue>
@@ -1666,6 +1820,13 @@ size_t LayerTreeHostImpl::GetFrameIndexForImage(const PaintImage& paint_image,
}
void LayerTreeHostImpl::NotifyReadyToActivate() {
+ // The TileManager may call this method while the pending tree is still being
+ // painted, as it isn't aware of the ongoing paint. We shouldn't tell the
+ // scheduler we are ready to activate in that case, as if we do it will
+ // immediately activate once we call NotifyPaintWorkletStateChange, rather
+ // than wait for the TileManager to actually raster the content!
+ if (!pending_tree_fully_painted_)
+ return;
pending_tree_raster_duration_timer_.reset();
client_->NotifyReadyToActivate();
}
@@ -1800,6 +1961,7 @@ void LayerTreeHostImpl::DidReceiveCompositorFrameAck() {
void LayerTreeHostImpl::DidPresentCompositorFrame(
uint32_t frame_token,
const gfx::PresentationFeedback& feedback) {
+ frame_trackers_.NotifyFramePresented(frame_token, feedback);
PresentationTimeCallbackBuffer::PendingCallbacks activated =
presentation_time_callbacks_.PopPendingCallbacks(frame_token);
@@ -1817,6 +1979,7 @@ void LayerTreeHostImpl::DidPresentCompositorFrame(
void LayerTreeHostImpl::DidNotNeedBeginFrame() {
skipped_frame_tracker_.WillNotProduceFrame();
+ frame_trackers_.NotifyPauseFrameProduction();
}
void LayerTreeHostImpl::ReclaimResources(
@@ -1909,7 +2072,6 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
metadata.page_scale_factor = active_tree_->current_page_scale_factor();
metadata.scrollable_viewport_size = active_tree_->ScrollableViewportSize();
metadata.root_background_color = active_tree_->background_color();
- metadata.content_source_id = active_tree_->content_source_id();
if (active_tree_->has_presentation_callbacks()) {
presentation_time_callbacks_.RegisterMainThreadPresentationCallbacks(
@@ -2061,6 +2223,7 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
if (frame->has_no_damage) {
DCHECK(!resourceless_software_draw_);
+ frame_trackers_.NotifyImplFrameCausedNoDamage(frame->begin_frame_ack);
TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoDamage", TRACE_EVENT_SCOPE_THREAD);
active_tree()->BreakSwapPromises(SwapPromise::SWAP_FAILS);
return false;
@@ -2070,10 +2233,26 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
active_tree_->source_frame_number());
auto compositor_frame = GenerateCompositorFrame(frame);
+ frame->frame_token = compositor_frame.metadata.frame_token;
layer_tree_frame_sink_->SubmitCompositorFrame(
std::move(compositor_frame),
/*hit_test_data_changed=*/false, debug_state_.show_hit_test_borders);
+ frame_trackers_.NotifySubmitFrame(compositor_frame.metadata.frame_token,
+ frame->begin_frame_ack,
+ frame->origin_begin_main_frame_args);
+ if (request_animation_frame_tracker_ &&
+ !mutator_host_->NextFrameHasPendingRAF()) {
+ frame_trackers_.ScheduleRemoval(
+ std::move(request_animation_frame_tracker_));
+ }
+
+ if (main_thread_animation_frame_tracker_ &&
+ mutator_host_->MainThreadAnimationsCount() == 0) {
+ frame_trackers_.ScheduleRemoval(
+ std::move(main_thread_animation_frame_tracker_));
+ }
+
// Clears the list of swap promises after calling DidSwap on each of them to
// signal that the swap is over.
active_tree()->ClearSwapPromises();
@@ -2097,7 +2276,6 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
FrameData* frame) {
- TRACE_EVENT0("cc,benchmark", "LayerTreeHostImpl::GenerateCompositorFrame");
TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
TRACE_ID_GLOBAL(CurrentBeginFrameArgs().trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
@@ -2177,15 +2355,15 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
ui::LatencyInfo& new_latency_info = metadata.latency_info.back();
if (CommitToActiveTree()) {
new_latency_info.AddLatencyNumberWithTimestamp(
- ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, frame_time, 1);
+ ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, frame_time);
} else {
new_latency_info.AddLatencyNumberWithTimestamp(
- ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, frame_time, 1);
+ ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, frame_time);
base::TimeTicks draw_time = base::TimeTicks::Now();
for (auto& latency : metadata.latency_info) {
latency.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, draw_time, 1);
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, draw_time);
}
}
ui::LatencyInfo::TraceIntermediateFlowEvents(metadata.latency_info,
@@ -2204,6 +2382,8 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
frame->begin_frame_ack.sequence_number);
metadata.begin_frame_ack = frame->begin_frame_ack;
+ metadata.mirror_rect = frame->mirror_rect;
+
viz::CompositorFrame compositor_frame;
compositor_frame.metadata = std::move(metadata);
resource_provider_.PrepareSendToParent(
@@ -2226,15 +2406,6 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
}
last_draw_local_surface_id_allocation_ =
child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation();
- if (const char* client_name = GetClientNameForMetrics()) {
- size_t total_quad_count = 0;
- for (const auto& pass : compositor_frame.render_pass_list)
- total_quad_count += pass->quad_list.size();
- UMA_HISTOGRAM_COUNTS_1000(
- base::StringPrintf("Compositing.%s.CompositorFrame.Quads", client_name),
- total_quad_count);
- }
-
return compositor_frame;
}
@@ -2305,13 +2476,16 @@ void LayerTreeHostImpl::GetGpuRasterizationCapabilities(
if (!*gpu_rasterization_enabled && !settings_.gpu_rasterization_forced)
return;
+ bool use_msaa = !caps.msaa_is_slow && !caps.avoid_stencil_buffers;
+
if (use_oop_rasterization_) {
*gpu_rasterization_supported = true;
*supports_disable_msaa = caps.multisample_compatibility;
// For OOP raster, the gpu service side will disable msaa if the
// requested samples are not enough. GPU raster does this same
// logic below client side.
- *max_msaa_samples = RequestedMSAASampleCount();
+ if (use_msaa)
+ *max_msaa_samples = RequestedMSAASampleCount();
return;
}
@@ -2326,7 +2500,7 @@ void LayerTreeHostImpl::GetGpuRasterizationCapabilities(
return;
*supports_disable_msaa = caps.multisample_compatibility;
- if (!caps.msaa_is_slow && !caps.avoid_stencil_buffers) {
+ if (use_msaa) {
// Skia may blacklist MSAA independently of Chrome. Query Skia for its max
// supported sample count. Assume gpu compositing + gpu raster for this, as
// that is what we are hoping to use.
@@ -2432,6 +2606,10 @@ void LayerTreeHostImpl::UpdateTreeResourcesForGpuRasterizationIfNeeded() {
bool LayerTreeHostImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
impl_thread_phase_ = ImplThreadPhase::INSIDE_IMPL_FRAME;
current_begin_frame_tracker_.Start(args);
+ frame_trackers_.NotifyBeginImplFrame(args);
+
+ begin_main_frame_expected_during_impl_ = client_->IsBeginMainFrameExpected();
+ begin_main_frame_sent_during_impl_ = false;
if (is_likely_to_require_a_draw_) {
// Optimistically schedule a draw. This will let us expect the tile manager
@@ -2440,8 +2618,10 @@ bool LayerTreeHostImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
SetNeedsRedraw();
}
- if (input_handler_client_)
- input_handler_client_->DeliverInputForBeginFrame();
+ if (input_handler_client_) {
+ scrollbar_controller_->WillBeginImplFrame();
+ input_handler_client_->DeliverInputForBeginFrame(args);
+ }
Animate();
@@ -2475,6 +2655,18 @@ bool LayerTreeHostImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
}
void LayerTreeHostImpl::DidFinishImplFrame() {
+ if (!begin_main_frame_sent_during_impl_ &&
+ !begin_main_frame_expected_during_impl_) {
+ // A begin-main-frame was never dispatched for this BeginFrameArgs, and one
+ // was not expected to be dispatched either. So notify the trackers of the
+ // begin-main-frame, and not to expect any updates from it. This is
+ // necessary to make sure the trackers can correctly know which frames were
+ // not expected to produce any updates.
+ frame_trackers_.NotifyBeginMainFrame(
+ current_begin_frame_tracker_.Current());
+ frame_trackers_.NotifyMainFrameCausedNoDamage(
+ current_begin_frame_tracker_.Current());
+ }
skipped_frame_tracker_.FinishFrame();
impl_thread_phase_ = ImplThreadPhase::IDLE;
current_begin_frame_tracker_.Finish();
@@ -2812,6 +3004,7 @@ void LayerTreeHostImpl::CreatePendingTree() {
active_tree()->top_controls_shown_ratio(),
active_tree()->elastic_overscroll());
}
+ pending_tree_fully_painted_ = false;
client_->OnCanDrawStateChanged(CanDraw());
TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get());
@@ -2967,7 +3160,11 @@ void LayerTreeHostImpl::ActivateSyncTree() {
// Dump property trees and layers if run with:
// --vmodule=layer_tree_host_impl=3
if (VLOG_IS_ON(3)) {
- VLOG(3) << "After activating sync tree, the active tree:"
+ const char* client_name = GetClientNameForMetrics();
+ if (!client_name)
+ client_name = "<unknown client>";
+ VLOG(3) << "After activating (" << client_name
+ << ") sync tree, the active tree:"
<< "\nproperty_trees:\n"
<< active_tree_->property_trees()->ToString() << "\n"
<< "cc::LayerImpls:\n"
@@ -3204,7 +3401,7 @@ void LayerTreeHostImpl::SetLayerTreeMutator(
void LayerTreeHostImpl::SetPaintWorkletLayerPainter(
std::unique_ptr<PaintWorkletLayerPainter> painter) {
- tile_manager_.SetPaintWorkletLayerPainter(std::move(painter));
+ paint_worklet_painter_ = std::move(painter);
}
LayerImpl* LayerTreeHostImpl::ViewportMainScrollLayer() {
@@ -3320,6 +3517,14 @@ void LayerTreeHostImpl::ReleaseLayerTreeFrameSink() {
bool all_resources_are_lost = layer_tree_frame_sink_->context_provider();
+ // Destroy the submit-frame trackers before destroying the frame sink.
+ pinch_frame_tracker_ = nullptr;
+ scroll_frame_tracker_ = nullptr;
+ compositor_animation_frame_tracker_ = nullptr;
+ request_animation_frame_tracker_ = nullptr;
+ main_thread_animation_frame_tracker_ = nullptr;
+ frame_trackers_.ClearAll();
+
// Detach from the old LayerTreeFrameSink and reset |layer_tree_frame_sink_|
// pointer as this surface is going to be destroyed independent of if binding
// the new LayerTreeFrameSink succeeds or not.
@@ -3329,15 +3534,24 @@ void LayerTreeHostImpl::ReleaseLayerTreeFrameSink() {
// If gpu compositing, then any resources created with the gpu context in the
// LayerTreeFrameSink were exported to the display compositor may be modified
// by it, and thus we would be unable to determine what state they are in, in
- // order to reuse them, so they must be lost. In software compositing, the
- // resources are not modified by the display compositor (there is no stateful
- // metadata for shared memory), so we do not need to consider them lost.
+ // order to reuse them, so they must be lost. Note that this includes
+ // resources created using the gpu context associated with
+ // |layer_tree_frame_sink_| internally by the compositor and any resources
+ // received from an external source (for instance, TextureLayers). This is
+ // because the API contract for releasing these external resources requires
+ // that the compositor return them with a valid sync token and no
+ // modifications to their GL state. Since that can not be guaranteed, these
+ // must also be marked lost.
+ //
+ // In software compositing, the resources are not modified by the display
+ // compositor (there is no stateful metadata for shared memory), so we do not
+ // need to consider them lost.
//
// In both cases, the resources that are exported to the display compositor
// will have no means of being returned to this client without the
- // LayerTreeFrameSink, so they should no longer be considered as exported.
- // Do this *after* any interactions with the |layer_tree_frame_sink_| in case
- // it tries to return resources during destruction.
+ // LayerTreeFrameSink, so they should no longer be considered as exported. Do
+ // this *after* any interactions with the |layer_tree_frame_sink_| in case it
+ // tries to return resources during destruction.
//
// The assumption being made here is that the display compositor WILL NOT use
// any resources previously exported when the CompositorFrameSink is closed.
@@ -3472,7 +3686,6 @@ void LayerTreeHostImpl::BindToClient(InputHandlerClient* client) {
InputHandler::ScrollStatus LayerTreeHostImpl::TryScroll(
const gfx::PointF& screen_space_point,
- InputHandler::ScrollInputType type,
const ScrollTree& scroll_tree,
ScrollNode* scroll_node) const {
InputHandler::ScrollStatus scroll_status;
@@ -3516,29 +3729,6 @@ InputHandler::ScrollStatus LayerTreeHostImpl::TryScroll(
return scroll_status;
}
- if (layer && !layer->non_fast_scrollable_region().IsEmpty()) {
- bool clipped = false;
- gfx::Transform inverse_screen_space_transform(
- gfx::Transform::kSkipInitialization);
- if (!screen_space_transform.GetInverse(&inverse_screen_space_transform)) {
- // TODO(shawnsingh): We shouldn't be applying a projection if screen space
- // transform is uninvertible here. Perhaps we should be returning
- // SCROLL_ON_MAIN_THREAD in this case?
- }
-
- gfx::PointF hit_test_point_in_layer_space = MathUtil::ProjectPoint(
- inverse_screen_space_transform, screen_space_point, &clipped);
- if (!clipped && layer->non_fast_scrollable_region().Contains(
- gfx::ToRoundedPoint(hit_test_point_in_layer_space))) {
- TRACE_EVENT0("cc",
- "LayerImpl::tryScroll: Failed NonFastScrollableRegion");
- scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
- scroll_status.main_thread_scrolling_reasons =
- MainThreadScrollingReason::kNonFastScrollableRegion;
- return scroll_status;
- }
- }
-
if (!scroll_node->scrollable) {
TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored not scrollable");
scroll_status.thread = InputHandler::SCROLL_IGNORED;
@@ -3578,9 +3768,21 @@ static bool IsMainThreadScrolling(const InputHandler::ScrollStatus& status,
return false;
}
+base::flat_set<int> LayerTreeHostImpl::NonFastScrollableNodes(
+ const gfx::PointF& device_viewport_point) const {
+ base::flat_set<int> non_fast_scrollable_nodes;
+
+ const auto& non_fast_layers =
+ active_tree_->FindLayersHitByPointInNonFastScrollableRegion(
+ device_viewport_point);
+ for (const auto* layer : non_fast_layers)
+ non_fast_scrollable_nodes.insert(layer->scroll_tree_index());
+
+ return non_fast_scrollable_nodes;
+}
+
ScrollNode* LayerTreeHostImpl::FindScrollNodeForDeviceViewportPoint(
const gfx::PointF& device_viewport_point,
- InputHandler::ScrollInputType type,
LayerImpl* layer_impl,
bool* scroll_on_main_thread,
uint32_t* main_thread_scrolling_reasons) const {
@@ -3589,6 +3791,9 @@ ScrollNode* LayerTreeHostImpl::FindScrollNodeForDeviceViewportPoint(
*main_thread_scrolling_reasons =
MainThreadScrollingReason::kNotScrollingOnMain;
+ const auto& non_fast_scrollable_nodes =
+ NonFastScrollableNodes(device_viewport_point);
+
// Walk up the hierarchy and look for a scrollable layer.
ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree;
ScrollNode* impl_scroll_node = nullptr;
@@ -3611,13 +3816,20 @@ ScrollNode* LayerTreeHostImpl::FindScrollNodeForDeviceViewportPoint(
// The content layer can also block attempts to scroll outside the main
// thread.
ScrollStatus status =
- TryScroll(device_viewport_point, type, scroll_tree, scroll_node);
+ TryScroll(device_viewport_point, scroll_tree, scroll_node);
if (IsMainThreadScrolling(status, scroll_node)) {
*scroll_on_main_thread = true;
*main_thread_scrolling_reasons = status.main_thread_scrolling_reasons;
return scroll_node;
}
+ if (non_fast_scrollable_nodes.contains(scroll_node->id)) {
+ *scroll_on_main_thread = true;
+ *main_thread_scrolling_reasons =
+ MainThreadScrollingReason::kNonFastScrollableRegion;
+ return scroll_node;
+ }
+
if (status.thread == InputHandler::SCROLL_ON_IMPL_THREAD &&
!impl_scroll_node) {
impl_scroll_node = scroll_node;
@@ -3638,10 +3850,14 @@ ScrollNode* LayerTreeHostImpl::FindScrollNodeForDeviceViewportPoint(
if (impl_scroll_node) {
// Ensure that final layer scrolls on impl thread (crbug.com/625100)
ScrollStatus status =
- TryScroll(device_viewport_point, type, scroll_tree, impl_scroll_node);
+ TryScroll(device_viewport_point, scroll_tree, impl_scroll_node);
if (IsMainThreadScrolling(status, impl_scroll_node)) {
*scroll_on_main_thread = true;
*main_thread_scrolling_reasons = status.main_thread_scrolling_reasons;
+ } else if (non_fast_scrollable_nodes.contains(impl_scroll_node->id)) {
+ *scroll_on_main_thread = true;
+ *main_thread_scrolling_reasons =
+ MainThreadScrollingReason::kNonFastScrollableRegion;
}
}
@@ -3710,10 +3926,13 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBeginImpl(
scroll_status.bubble = true;
}
+ scroll_frame_tracker_ = frame_trackers_.CreateTracker(
+ wheel_scrolling_ ? FrameSequenceTrackerType::kWheelScroll
+ : FrameSequenceTrackerType::kTouchScroll);
client_->RenewTreePriority();
RecordCompositorSlowScrollMetric(type, CC_THREAD);
- UpdateScrollSourceInfo(type);
+ UpdateScrollSourceInfo(type, scroll_state);
return scroll_status;
}
@@ -3796,7 +4015,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin(
}
scrolling_node = FindScrollNodeForDeviceViewportPoint(
- device_viewport_point, type, layer_impl, &scroll_on_main_thread,
+ device_viewport_point, layer_impl, &scroll_on_main_thread,
&scroll_status.main_thread_scrolling_reasons);
}
@@ -3943,14 +4162,31 @@ gfx::Vector2dF LayerTreeHostImpl::ComputeScrollDelta(
return gfx::Vector2dF(scrolled.x(), scrolled.y());
}
+bool LayerTreeHostImpl::AutoScrollAnimationCreate(ScrollNode* scroll_node,
+ const gfx::Vector2dF& delta,
+ float autoscroll_velocity) {
+ return ScrollAnimationCreateInternal(scroll_node, delta, base::TimeDelta(),
+ autoscroll_velocity);
+}
+
bool LayerTreeHostImpl::ScrollAnimationCreate(ScrollNode* scroll_node,
const gfx::Vector2dF& delta,
base::TimeDelta delayed_by) {
+ return ScrollAnimationCreateInternal(scroll_node, delta, delayed_by,
+ base::nullopt);
+}
+
+bool LayerTreeHostImpl::ScrollAnimationCreateInternal(
+ ScrollNode* scroll_node,
+ const gfx::Vector2dF& delta,
+ base::TimeDelta delayed_by,
+ base::Optional<float> autoscroll_velocity) {
ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree;
const float kEpsilon = 0.1f;
bool scroll_animated =
- (std::abs(delta.x()) > kEpsilon || std::abs(delta.y()) > kEpsilon);
+ (std::abs(delta.x()) > kEpsilon || std::abs(delta.y()) > kEpsilon) ||
+ autoscroll_velocity;
if (!scroll_animated) {
scroll_tree.ScrollBy(scroll_node, delta, active_tree());
TRACE_EVENT_INSTANT0("cc", "no scroll animation due to small delta",
@@ -3970,9 +4206,15 @@ bool LayerTreeHostImpl::ScrollAnimationCreate(ScrollNode* scroll_node,
// input latency tracking architecture from working.
base::TimeDelta animation_start_offset = CurrentBeginFrameArgs().interval;
- mutator_host_->ImplOnlyScrollAnimationCreate(
- scroll_node->element_id, target_offset, current_offset, delayed_by,
- animation_start_offset);
+ if (autoscroll_velocity) {
+ mutator_host_->ImplOnlyAutoScrollAnimationCreate(
+ scroll_node->element_id, gfx::ScrollOffset(delta), current_offset,
+ autoscroll_velocity.value(), animation_start_offset);
+ } else {
+ mutator_host_->ImplOnlyScrollAnimationCreate(
+ scroll_node->element_id, target_offset, current_offset, delayed_by,
+ animation_start_offset);
+ }
SetNeedsOneBeginImplFrame();
@@ -4762,6 +5004,7 @@ void LayerTreeHostImpl::ScrollEndImpl(ScrollState* scroll_state) {
DistributeScrollDelta(scroll_state);
browser_controls_offset_manager_->ScrollEnd();
ClearCurrentlyScrollingNode();
+ frame_trackers_.ScheduleRemoval(std::move(scroll_frame_tracker_));
}
void LayerTreeHostImpl::ScrollEnd(ScrollState* scroll_state, bool should_snap) {
@@ -4843,8 +5086,8 @@ InputHandlerPointerResult LayerTreeHostImpl::MouseMoveAt(
bool scroll_on_main_thread = false;
uint32_t main_thread_scrolling_reasons;
auto* scroll_node = FindScrollNodeForDeviceViewportPoint(
- device_viewport_point, InputHandler::TOUCHSCREEN, layer_impl,
- &scroll_on_main_thread, &main_thread_scrolling_reasons);
+ device_viewport_point, layer_impl, &scroll_on_main_thread,
+ &main_thread_scrolling_reasons);
if (scroll_node)
scroll_element_id = scroll_node->element_id;
@@ -4895,6 +5138,8 @@ void LayerTreeHostImpl::PinchGestureBegin() {
OuterViewportScrollNode() ? false : true);
active_tree_->SetCurrentlyScrollingNode(OuterViewportScrollNode());
browser_controls_offset_manager_->PinchBegin();
+ pinch_frame_tracker_ =
+ frame_trackers_.CreateTracker(FrameSequenceTrackerType::kPinchZoom);
}
void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta,
@@ -4902,6 +5147,7 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta,
TRACE_EVENT0("cc", "LayerTreeHostImpl::PinchGestureUpdate");
if (!InnerViewportScrollNode())
return;
+ has_pinch_zoomed_ = true;
viewport()->PinchUpdate(magnify_delta, anchor);
client_->SetNeedsCommitOnImplThread();
SetNeedsRedraw();
@@ -4926,6 +5172,7 @@ void LayerTreeHostImpl::PinchGestureEnd(const gfx::Point& anchor,
// scales that we want when we're not inside a pinch.
active_tree_->set_needs_update_draw_properties();
SetNeedsRedraw();
+ frame_trackers_.ScheduleRemoval(std::move(pinch_frame_tracker_));
}
void LayerTreeHostImpl::CollectScrollDeltas(
@@ -4971,10 +5218,23 @@ std::unique_ptr<ScrollAndScaleSet> LayerTreeHostImpl::ProcessScrollDeltas() {
scroll_info->swap_promises.swap(swap_promises_for_main_thread_scroll_update_);
// Record and reset scroll source flags.
- scroll_info->has_scrolled_by_wheel = has_scrolled_by_wheel_;
- scroll_info->has_scrolled_by_touch = has_scrolled_by_touch_;
+ if (has_scrolled_by_wheel_) {
+ scroll_info->manipulation_info |= kManipulationInfoHasScrolledByWheel;
+ }
+ if (has_scrolled_by_touch_) {
+ scroll_info->manipulation_info |= kManipulationInfoHasScrolledByTouch;
+ }
+ if (has_scrolled_by_precisiontouchpad_) {
+ scroll_info->manipulation_info |=
+ kManipulationInfoHasScrolledByPrecisionTouchPad;
+ }
+ if (has_pinch_zoomed_) {
+ scroll_info->manipulation_info |= kManipulationInfoHasPinchZoomed;
+ }
+
+ has_scrolled_by_wheel_ = has_scrolled_by_touch_ =
+ has_scrolled_by_precisiontouchpad_ = has_pinch_zoomed_ = false;
scroll_info->scroll_gesture_did_end = scroll_gesture_did_end_;
- has_scrolled_by_wheel_ = has_scrolled_by_touch_ = false;
// Record and reset overscroll delta.
scroll_info->overscroll_delta = overscroll_delta_for_main_thread_;
@@ -5091,8 +5351,17 @@ bool LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time,
// TODO(crbug.com/551138): We currently have a single signal from the
// animation_host, so on the last frame of an animation we will
// still request an extra SetNeedsAnimate here.
- if (animated)
+ if (animated) {
SetNeedsOneBeginImplFrame();
+ if (!compositor_animation_frame_tracker_) {
+ compositor_animation_frame_tracker_ = frame_trackers_.CreateTracker(
+ FrameSequenceTrackerType::kCompositorAnimation);
+ }
+ } else {
+ frame_trackers_.ScheduleRemoval(
+ std::move(compositor_animation_frame_tracker_));
+ }
+
// TODO(crbug.com/551138): We could return true only if the animaitons are on
// the active tree. There's no need to cause a draw to take place from
// animations starting/ticking on the pending tree.
@@ -5371,7 +5640,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
GLenum texture_target = GL_TEXTURE_2D;
// For software compositing, shared memory will be allocated and the
// UIResource will be copied into it.
- base::MappedReadOnlyRegion mapped_region;
+ base::MappedReadOnlyRegion shm;
viz::SharedBitmapId shared_bitmap_id;
bool overlay_candidate = false;
@@ -5389,8 +5658,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
BufferFormat(format), caps);
}
} else {
- mapped_region =
- viz::bitmap_allocation::AllocateSharedBitmap(upload_size, format);
+ shm = viz::bitmap_allocation::AllocateSharedBitmap(upload_size, format);
shared_bitmap_id = viz::SharedBitmap::GenerateId();
}
@@ -5415,7 +5683,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
SkImageInfo::MakeN32Premul(gfx::SizeToSkISize(upload_size));
sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(
- dst_info, mapped_region.mapping.memory(), dst_info.minRowBytes());
+ dst_info, shm.mapping.memory(), dst_info.minRowBytes());
surface->getCanvas()->writePixels(
src_info, const_cast<uint8_t*>(bitmap.GetPixels()),
src_info.minRowBytes(), 0, 0);
@@ -5451,7 +5719,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
SkImageInfo dst_info =
SkImageInfo::MakeN32Premul(gfx::SizeToSkISize(upload_size));
scaled_surface = SkSurface::MakeRasterDirect(
- dst_info, mapped_region.mapping.memory(), dst_info.minRowBytes());
+ dst_info, shm.mapping.memory(), dst_info.minRowBytes());
}
SkCanvas* scaled_canvas = scaled_surface->getCanvas();
scaled_canvas->scale(canvas_scale_x, canvas_scale_y);
@@ -5494,9 +5762,8 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
overlay_candidate);
transferable.format = format;
} else {
- layer_tree_frame_sink_->DidAllocateSharedBitmap(
- viz::bitmap_allocation::ToMojoHandle(std::move(mapped_region.region)),
- shared_bitmap_id);
+ layer_tree_frame_sink_->DidAllocateSharedBitmap(std::move(shm.region),
+ shared_bitmap_id);
transferable = viz::TransferableResource::MakeSoftware(shared_bitmap_id,
upload_size, format);
}
@@ -5514,7 +5781,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
data.opaque = bitmap.GetOpaque();
data.format = format;
data.shared_bitmap_id = shared_bitmap_id;
- data.shared_mapping = std::move(mapped_region.mapping);
+ data.shared_mapping = std::move(shm.mapping);
data.mailbox = mailbox;
data.resource_id_for_export = id;
ui_resource_map_[uid] = std::move(data);
@@ -5916,11 +6183,18 @@ void LayerTreeHostImpl::SetContextVisibility(bool is_visible) {
}
void LayerTreeHostImpl::UpdateScrollSourceInfo(
- InputHandler::ScrollInputType type) {
- if (type == InputHandler::WHEEL)
+ InputHandler::ScrollInputType type,
+ ScrollState* scroll_state) {
+ if (type == InputHandler::WHEEL &&
+ scroll_state->delta_granularity() ==
+ static_cast<double>(
+ ui::input_types::ScrollGranularity::kScrollByPrecisePixel)) {
+ has_scrolled_by_precisiontouchpad_ = true;
+ } else if (type == InputHandler::WHEEL) {
has_scrolled_by_wheel_ = true;
- else if (type == InputHandler::TOUCHSCREEN)
+ } else if (type == InputHandler::TOUCHSCREEN) {
has_scrolled_by_touch_ = true;
+ }
}
void LayerTreeHostImpl::ShowScrollbarsForImplScroll(ElementId element_id) {
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index bb89bc998a4..ca403dbfd97 100644
--- a/chromium/cc/trees/layer_tree_host_impl.h
+++ b/chromium/cc/trees/layer_tree_host_impl.h
@@ -27,14 +27,17 @@
#include "cc/input/scrollbar_animation_controller.h"
#include "cc/input/scrollbar_controller.h"
#include "cc/layers/layer_collections.h"
+#include "cc/paint/paint_worklet_job.h"
#include "cc/resources/ui_resource_client.h"
#include "cc/scheduler/begin_frame_tracker.h"
#include "cc/scheduler/commit_earlyout_reason.h"
#include "cc/scheduler/draw_result.h"
+#include "cc/scheduler/scheduler.h"
#include "cc/scheduler/video_frame_controller.h"
#include "cc/tiles/decoded_image_tracker.h"
#include "cc/tiles/image_decode_cache.h"
#include "cc/tiles/tile_manager.h"
+#include "cc/trees/frame_sequence_tracker.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_mutator.h"
@@ -156,10 +159,16 @@ class LayerTreeHostImplClient {
std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
const gfx::PresentationFeedback& feedback) = 0;
+ // Returns whether the main-thread is expected to receive a BeginMainFrame.
+ virtual bool IsBeginMainFrameExpected() = 0;
+
virtual void NotifyAnimationWorkletStateChange(
AnimationWorkletMutationState state,
ElementListType tree_type) = 0;
+ virtual void NotifyPaintWorkletStateChange(
+ Scheduler::PaintWorkletState state) = 0;
+
protected:
virtual ~LayerTreeHostImplClient() {}
};
@@ -187,6 +196,9 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
FrameData& operator=(const FrameData&) = delete;
void AsValueInto(base::trace_event::TracedValue* value) const;
+ uint32_t frame_token = 0;
+ // frame_token is populated by the LayerTreeHostImpl when submitted.
+
std::vector<viz::SurfaceId> activation_dependencies;
base::Optional<uint32_t> deadline_in_frames;
bool use_default_lower_bound_deadline = false;
@@ -196,6 +208,13 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
bool has_no_damage = false;
bool may_contain_video = false;
viz::BeginFrameAck begin_frame_ack;
+ // The original BeginFrameArgs that triggered the latest update from the
+ // main thread.
+ viz::BeginFrameArgs origin_begin_main_frame_args;
+
+ // Union of visible rects of MirrorLayers in the frame, used to force damage
+ // on the surface.
+ gfx::Rect mirror_rect;
};
// A struct of data for a single UIResource, including the backing
@@ -275,8 +294,7 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
void SetNeedsAnimateInput() override;
bool IsCurrentlyScrollingViewport() const override;
bool IsCurrentlyScrollingLayerAt(
- const gfx::Point& viewport_point,
- InputHandler::ScrollInputType type) const override;
+ const gfx::Point& viewport_point) const override;
EventListenerProperties GetEventListenerProperties(
EventListenerClass event_class) const override;
InputHandler::TouchStartOrMoveEventListenerType
@@ -320,10 +338,11 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
}
virtual void WillSendBeginMainFrame() {}
- virtual void DidSendBeginMainFrame() {}
+ virtual void DidSendBeginMainFrame(const viz::BeginFrameArgs& args);
virtual void BeginMainFrameAborted(
CommitEarlyOutReason reason,
- std::vector<std::unique_ptr<SwapPromise>> swap_promises);
+ std::vector<std::unique_ptr<SwapPromise>> swap_promises,
+ const viz::BeginFrameArgs& args);
virtual void ReadyToCommit() {} // For tests.
virtual void BeginCommit();
virtual void CommitComplete();
@@ -432,6 +451,8 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
DrawMode GetDrawMode() const;
+ void DidNotNeedBeginFrame();
+
// TileManagerClient implementation.
void NotifyReadyToActivate() override;
void NotifyReadyToDraw() override;
@@ -471,7 +492,6 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
void DidPresentCompositorFrame(
uint32_t frame_token,
const gfx::PresentationFeedback& feedback) override;
- void DidNotNeedBeginFrame() override;
void ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) override;
void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
@@ -506,6 +526,7 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
int* max_msaa_samples,
bool* supports_disable_msaa);
bool use_gpu_rasterization() const { return use_gpu_rasterization_; }
+ bool use_oop_rasterization() const { return use_oop_rasterization_; }
bool use_msaa() const { return use_msaa_; }
GpuRasterizationStatus gpu_rasterization_status() const {
@@ -710,19 +731,30 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
}
InputHandler::ScrollStatus TryScroll(const gfx::PointF& screen_space_point,
- InputHandler::ScrollInputType type,
const ScrollTree& scroll_tree,
ScrollNode* scroll_node) const;
+ // Return all ScrollNode indices that have an associated layer with a non-fast
+ // region that intersects the point.
+ base::flat_set<int> NonFastScrollableNodes(
+ const gfx::PointF& device_viewport_point) const;
+
// Returns true if a scroll offset animation is created and false if we scroll
// by the desired amount without an animation.
bool ScrollAnimationCreate(ScrollNode* scroll_node,
const gfx::Vector2dF& scroll_amount,
base::TimeDelta delayed_by);
+ bool AutoScrollAnimationCreate(ScrollNode* scroll_node,
+ const gfx::Vector2dF& scroll_amount,
+ float autoscroll_velocity);
void SetLayerTreeMutator(std::unique_ptr<LayerTreeMutator> mutator);
+
void SetPaintWorkletLayerPainter(
std::unique_ptr<PaintWorkletLayerPainter> painter);
+ PaintWorkletLayerPainter* GetPaintWorkletLayerPainterForTesting() const {
+ return paint_worklet_painter_.get();
+ }
// The viewport has two scroll nodes, corresponding to the visual and layout
// viewports. However, when we compute the scroll chain we include only one
@@ -759,6 +791,10 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
return compositor_frame_reporting_controller_.get();
}
+ void set_pending_tree_fully_painted_for_testing(bool painted) {
+ pending_tree_fully_painted_ = painted;
+ }
+
protected:
LayerTreeHostImpl(
const LayerTreeSettings& settings,
@@ -810,6 +846,10 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
const gfx::PointF& viewport_point,
const gfx::Vector2dF& viewport_delta,
ScrollTree* scroll_tree);
+ bool ScrollAnimationCreateInternal(ScrollNode* scroll_node,
+ const gfx::Vector2dF& delta,
+ base::TimeDelta delayed_by,
+ base::Optional<float> autoscroll_velocity);
void CleanUpTileManagerResources();
void CreateTileManagerResources();
@@ -824,6 +864,18 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
// impl thread.
void UpdateSyncTreeAfterCommitOrImplSideInvalidation();
+ // Returns a job map for all 'dirty' PaintWorklets, e.g. PaintWorkletInputs
+ // that do not map to a PaintRecord.
+ PaintWorkletJobMap GatherDirtyPaintWorklets() const;
+
+ // Called when all PaintWorklet results are ready (i.e. have been painted) for
+ // the current pending tree.
+ void OnPaintWorkletResultsReady(PaintWorkletJobMap results);
+
+ // Called when the pending tree has been fully painted, i.e. all required data
+ // is available to raster the tree.
+ void NotifyPendingTreeFullyPainted();
+
// Returns true if status changed.
bool UpdateGpuRasterizationStatus();
void UpdateTreeResourcesForGpuRasterizationIfNeeded();
@@ -862,7 +914,6 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
ScrollNode* FindScrollNodeForDeviceViewportPoint(
const gfx::PointF& device_viewport_point,
- InputHandler::ScrollInputType type,
LayerImpl* layer_hit_by_point,
bool* scroll_on_main_thread,
uint32_t* main_thread_scrolling_reason) const;
@@ -910,7 +961,8 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
// thread side to keep track of the frequency of scrolling with different
// sources per page load. TODO(crbug.com/691886): Use GRC API to plumb the
// scroll source info for Use Counters.
- void UpdateScrollSourceInfo(InputHandler::ScrollInputType type);
+ void UpdateScrollSourceInfo(InputHandler::ScrollInputType type,
+ ScrollState* scroll_state);
bool IsScrolledBy(LayerImpl* child, ScrollNode* ancestor);
void ShowScrollbarsForImplScroll(ElementId element_id);
@@ -931,6 +983,13 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
void AllocateLocalSurfaceId();
const LayerTreeSettings settings_;
+
+ // This is set to true only if:
+ // . The compositor is running single-threaded (i.e. there is no separate
+ // compositor/impl thread).
+ // . There is no scheduler (which means layer-update, composite, etc. steps
+ // happen explicitly via. synchronous calls to appropriate functions).
+ // This is usually turned on only in some tests (e.g. web-tests).
const bool is_synchronous_single_threaded_;
const int default_color_space_id_ = gfx::ColorSpace::GetNextId();
@@ -1138,13 +1197,21 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
// success) state.
std::vector<std::pair<int, bool>> completed_image_decode_requests_;
- // These are used to transfer usage of touch and wheel scrolls to the main
- // thread.
+ // These are used to transfer usage of different types of scrolling to the
+ // main thread.
bool has_scrolled_by_wheel_ = false;
bool has_scrolled_by_touch_ = false;
+ bool has_scrolled_by_precisiontouchpad_ = false;
+ bool has_pinch_zoomed_ = false;
ImplThreadPhase impl_thread_phase_ = ImplThreadPhase::IDLE;
+ // Tracks whether a BeginMainFrame is expected to be dispatched during an
+ // 'impl frame' (i.e. between WillBeginImplFrame() and DidFinishImplFrame()),
+ // and whether it was actually dispatched during the impl frame.
+ bool begin_main_frame_expected_during_impl_ = false;
+ bool begin_main_frame_sent_during_impl_ = false;
+
ImageAnimationController image_animation_controller_;
std::unique_ptr<UkmManager> ukm_manager_;
@@ -1172,6 +1239,13 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
// Manages composited scrollbar hit testing.
std::unique_ptr<ScrollbarController> scrollbar_controller_;
+ FrameSequenceTrackerCollection frame_trackers_;
+ std::unique_ptr<FrameSequenceTracker> pinch_frame_tracker_;
+ std::unique_ptr<FrameSequenceTracker> scroll_frame_tracker_;
+ std::unique_ptr<FrameSequenceTracker> compositor_animation_frame_tracker_;
+ std::unique_ptr<FrameSequenceTracker> request_animation_frame_tracker_;
+ std::unique_ptr<FrameSequenceTracker> main_thread_animation_frame_tracker_;
+
// Set to true when a scroll gesture being handled on the compositor has
// ended. i.e. When a GSE has arrived and any ongoing scroll animation has
// ended.
@@ -1187,9 +1261,18 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
// once the animation is over.
base::Optional<ScrollState> deferred_scroll_end_state_;
+ // PaintWorklet painting is controlled from the LayerTreeHostImpl, dispatched
+ // to the worklet thread via |paint_worklet_painter_|.
+ std::unique_ptr<PaintWorkletLayerPainter> paint_worklet_painter_;
+
+ // While PaintWorklet painting is ongoing the PendingTree is not yet fully
+ // painted and cannot be rastered or activated. This boolean tracks whether or
+ // not we are in that state.
+ bool pending_tree_fully_painted_ = false;
+
// Must be the last member to ensure this is destroyed first in the
// destruction order and invalidates all weak pointers.
- base::WeakPtrFactory<LayerTreeHostImpl> weak_factory_;
+ base::WeakPtrFactory<LayerTreeHostImpl> weak_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
index 80d1f14a001..24ceca1c40c 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -55,6 +55,8 @@
#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/skia_common.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
+#include "cc/test/test_paint_worklet_layer_painter.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/clip_node.h"
#include "cc/trees/draw_property_utils.h"
@@ -81,7 +83,6 @@
#include "components/viz/test/begin_frame_args_test.h"
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/fake_skia_output_surface.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "media/base/media.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -135,6 +136,7 @@ class LayerTreeHostImplTest : public testing::Test,
did_request_redraw_(false),
did_request_next_frame_(false),
did_request_prepare_tiles_(false),
+ did_prepare_tiles_(false),
did_complete_page_scale_animation_(false),
reduce_memory_result_(true),
did_request_impl_side_invalidation_(false) {
@@ -159,6 +161,13 @@ class LayerTreeHostImplTest : public testing::Test,
host_impl_->active_tree()->GetDeviceViewport().size());
pending_tree->SetDeviceScaleFactor(
host_impl_->active_tree()->device_scale_factor());
+ // Normally a pending tree will not be fully painted until the commit has
+ // happened and any PaintWorklets have been resolved. However many of the
+ // unittests never actually commit the pending trees that they create, so to
+ // enable them to still treat the tree as painted we forcibly override the
+ // state here. Note that this marks a distinct departure from reality in the
+ // name of easier testing.
+ host_impl_->set_pending_tree_fully_painted_for_testing(true);
}
void TearDown() override {
@@ -189,6 +198,7 @@ class LayerTreeHostImplTest : public testing::Test,
void PostAnimationEventsToMainThreadOnImplThread(
std::unique_ptr<MutatorEvents> events) override {}
bool IsInsideDraw() override { return false; }
+ bool IsBeginMainFrameExpected() override { return true; }
void RenewTreePriority() override {}
void PostDelayedAnimationTaskOnImplThread(base::OnceClosure task,
base::TimeDelta delay) override {
@@ -203,7 +213,7 @@ class LayerTreeHostImplTest : public testing::Test,
base::TimeTicks::Now()));
}
void WillPrepareTiles() override {}
- void DidPrepareTiles() override {}
+ void DidPrepareTiles() override { did_prepare_tiles_ = true; }
void DidCompletePageScaleAnimationOnImplThread() override {
did_complete_page_scale_animation_ = true;
}
@@ -229,6 +239,8 @@ class LayerTreeHostImplTest : public testing::Test,
const gfx::PresentationFeedback& feedback) override {}
void NotifyAnimationWorkletStateChange(AnimationWorkletMutationState state,
ElementListType tree_type) override {}
+ void NotifyPaintWorkletStateChange(
+ Scheduler::PaintWorkletState state) override {}
void set_reduce_memory_result(bool reduce_memory_result) {
reduce_memory_result_ = reduce_memory_result;
@@ -796,6 +808,7 @@ class LayerTreeHostImplTest : public testing::Test,
bool did_request_redraw_;
bool did_request_next_frame_;
bool did_request_prepare_tiles_;
+ bool did_prepare_tiles_;
bool did_complete_page_scale_animation_;
bool reduce_memory_result_;
bool did_request_impl_side_invalidation_;
@@ -852,7 +865,8 @@ class TestInputHandlerClient : public InputHandlerClient {
min_page_scale_factor_ = min_page_scale_factor;
max_page_scale_factor_ = max_page_scale_factor;
}
- void DeliverInputForBeginFrame() override {}
+ void DeliverInputForBeginFrame(const viz::BeginFrameArgs& args) override {}
+ void DeliverInputForHighLatencyMode() override {}
gfx::ScrollOffset last_set_scroll_offset() { return last_set_scroll_offset_; }
@@ -1095,14 +1109,11 @@ TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) {
EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
status.main_thread_scrolling_reasons);
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
- InputHandler::WHEEL));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point()));
host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, 10),
- InputHandler::WHEEL));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, 10)));
host_impl_->ScrollEnd(EndState().get());
- EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
- InputHandler::WHEEL));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point()));
EXPECT_TRUE(did_request_redraw_);
EXPECT_TRUE(did_request_commit_);
}
@@ -1374,16 +1385,14 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) {
EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
status.main_thread_scrolling_reasons);
- EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
- InputHandler::WHEEL));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25)));
status = host_impl_->ScrollBegin(BeginState(gfx::Point(25, 25)).get(),
InputHandler::TOUCHSCREEN);
EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
status.main_thread_scrolling_reasons);
- EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(25, 25), InputHandler::TOUCHSCREEN));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25)));
// All scroll types outside this region should succeed.
status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(),
@@ -1392,26 +1401,21 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) {
EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
status.main_thread_scrolling_reasons);
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(75, 75), InputHandler::TOUCHSCREEN));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75)));
host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
- EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(25, 25), InputHandler::TOUCHSCREEN));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25)));
host_impl_->ScrollEnd(EndState().get());
- EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(75, 75), InputHandler::TOUCHSCREEN));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75)));
status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(),
InputHandler::TOUCHSCREEN);
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
status.main_thread_scrolling_reasons);
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(75, 75), InputHandler::TOUCHSCREEN));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75)));
host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
host_impl_->ScrollEnd(EndState().get());
- EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(75, 75), InputHandler::TOUCHSCREEN));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75)));
}
TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
@@ -1434,8 +1438,7 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
status.main_thread_scrolling_reasons);
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(40, 10),
- InputHandler::WHEEL));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(40, 10)));
host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 1)).get());
host_impl_->ScrollEnd(EndState().get());
@@ -10410,7 +10413,88 @@ TEST_F(LayerTreeHostImplTest,
EXPECT_FALSE(host_impl_->EvictedUIResourcesExist());
}
-class FrameSinkClient : public viz::TestLayerTreeFrameSinkClient {
+TEST_F(LayerTreeHostImplTest, ObeyMSAACaps) {
+ LayerTreeSettings msaaSettings = DefaultSettings();
+ msaaSettings.gpu_rasterization_msaa_sample_count = 4;
+
+ // gpu raster, msaa on
+ {
+ bool msaa_is_slow = false;
+ EXPECT_TRUE(CreateHostImpl(
+ msaaSettings,
+ FakeLayerTreeFrameSink::Create3dForGpuRasterization(
+ msaaSettings.gpu_rasterization_msaa_sample_count, msaa_is_slow)));
+
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->SetContentHasSlowPaths(true);
+ host_impl_->CommitComplete();
+
+ EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT,
+ host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+ EXPECT_FALSE(host_impl_->use_oop_rasterization());
+ EXPECT_TRUE(host_impl_->use_msaa());
+ }
+
+ // gpu raster, msaa off
+ {
+ bool msaa_is_slow = true;
+ EXPECT_TRUE(CreateHostImpl(
+ msaaSettings,
+ FakeLayerTreeFrameSink::Create3dForGpuRasterization(
+ msaaSettings.gpu_rasterization_msaa_sample_count, msaa_is_slow)));
+
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->SetContentHasSlowPaths(true);
+ host_impl_->CommitComplete();
+
+ EXPECT_EQ(GpuRasterizationStatus::ON,
+ host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+ EXPECT_FALSE(host_impl_->use_oop_rasterization());
+ EXPECT_FALSE(host_impl_->use_msaa());
+ }
+
+ // oop raster, msaa on
+ {
+ bool msaa_is_slow = false;
+ EXPECT_TRUE(CreateHostImpl(
+ msaaSettings,
+ FakeLayerTreeFrameSink::Create3dForOopRasterization(
+ msaaSettings.gpu_rasterization_msaa_sample_count, msaa_is_slow)));
+
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->SetContentHasSlowPaths(true);
+ host_impl_->CommitComplete();
+
+ EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT,
+ host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl_->use_oop_rasterization());
+ EXPECT_TRUE(host_impl_->use_msaa());
+ }
+
+ // oop raster, msaa off
+ {
+ bool msaa_is_slow = true;
+ EXPECT_TRUE(CreateHostImpl(
+ msaaSettings,
+ FakeLayerTreeFrameSink::Create3dForOopRasterization(
+ msaaSettings.gpu_rasterization_msaa_sample_count, msaa_is_slow)));
+
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->SetContentHasSlowPaths(true);
+ host_impl_->CommitComplete();
+
+ EXPECT_EQ(GpuRasterizationStatus::ON,
+ host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl_->use_oop_rasterization());
+ EXPECT_FALSE(host_impl_->use_msaa());
+ }
+}
+
+class FrameSinkClient : public TestLayerTreeFrameSinkClient {
public:
explicit FrameSinkClient(
scoped_refptr<viz::ContextProvider> display_context_provider)
@@ -10464,7 +10548,7 @@ TEST_P(LayerTreeHostImplTestWithRenderer, ShutdownReleasesContext) {
constexpr double refresh_rate = 60.0;
viz::RendererSettings renderer_settings = viz::RendererSettings();
renderer_settings.use_skia_renderer = renderer_type() == RENDERER_SKIA;
- auto layer_tree_frame_sink = std::make_unique<viz::TestLayerTreeFrameSink>(
+ auto layer_tree_frame_sink = std::make_unique<TestLayerTreeFrameSink>(
context_provider, viz::TestContextProvider::CreateWorker(), nullptr,
renderer_settings, base::ThreadTaskRunnerHandle::Get().get(),
synchronous_composite, disable_display_vsync, refresh_rate);
@@ -11611,16 +11695,14 @@ TEST_F(LayerTreeHostImplVirtualViewportTest,
->ScrollBegin(BeginState(gfx::Point()).get(),
InputHandler::TOUCHSCREEN)
.thread);
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(), InputHandler::TOUCHSCREEN));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point()));
// Scroll near the edge of the outer viewport.
gfx::Vector2d scroll_delta(inner_viewport.width() / 2.f,
inner_viewport.height() / 2.f);
host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
inner_expected += scroll_delta;
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(), InputHandler::TOUCHSCREEN));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point()));
EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
@@ -11630,13 +11712,11 @@ TEST_F(LayerTreeHostImplVirtualViewportTest,
// and outer viewport layers is perfect.
host_impl_->ScrollBy(
UpdateState(gfx::Point(), gfx::ScaleVector2d(scroll_delta, 2)).get());
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(), InputHandler::TOUCHSCREEN));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point()));
outer_expected += scroll_delta;
inner_expected += scroll_delta;
host_impl_->ScrollEnd(EndState().get());
- EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(), InputHandler::TOUCHSCREEN));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point()));
EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
@@ -12452,16 +12532,13 @@ TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimatedAborted) {
host_impl_
->ScrollBegin(BeginState(gfx::Point(0, y)).get(), InputHandler::WHEEL)
.thread);
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, y),
- InputHandler::WHEEL));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, y)));
host_impl_->ScrollBy(
UpdateState(gfx::Point(0, y), gfx::Vector2d(0, 50)).get());
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, y + 50),
- InputHandler::WHEEL));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, y + 50)));
std::unique_ptr<ScrollState> scroll_state_end = EndState();
host_impl_->ScrollEnd(scroll_state_end.get());
- EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
- InputHandler::WHEEL));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point()));
// The instant scroll should have marked the smooth scroll animation as
// aborted.
@@ -12851,7 +12928,7 @@ TEST_F(LayerTreeHostImplTest, InvalidLayerNotAddedToRasterQueue) {
layer->SetDrawsContent(true);
layer->tilings()->AddTiling(gfx::AxisTransform2d(), raster_source_with_tiles);
layer->UpdateRasterSource(raster_source_with_tiles, &empty_invalidation,
- nullptr);
+ nullptr, nullptr);
layer->tilings()->tiling_at(0)->set_resolution(
TileResolution::HIGH_RESOLUTION);
layer->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -13447,9 +13524,7 @@ TEST_F(LayerTreeHostImplTest, UpdatePageScaleFactorOnActiveTree) {
CreateScrollAndContentsLayers(host_impl_->pending_tree(),
gfx::Size(100, 100));
host_impl_->pending_tree()->BuildPropertyTreesForTesting();
- LOG(ERROR) << "ACTIVATE SYNC TREE";
host_impl_->ActivateSyncTree();
- LOG(ERROR) << "DONE ACTIVATE SYNC TREE";
DrawFrame();
CreatePendingTree();
@@ -13475,9 +13550,7 @@ TEST_F(LayerTreeHostImplTest, UpdatePageScaleFactorOnActiveTree) {
page_scale_layer->transform_tree_index());
EXPECT_EQ(pending_tree_node->post_local_scale_factor, 2.f);
- LOG(ERROR) << "2 ACTIVATE SYNC TREE";
host_impl_->ActivateSyncTree();
- LOG(ERROR) << "DONE 2 ACTIVATE SYNC TREE";
host_impl_->active_tree()->UpdateDrawProperties();
active_tree_node =
host_impl_->active_tree()->property_trees()->transform_tree.Node(
@@ -14839,5 +14912,194 @@ TEST_F(LayerTreeHostImplTest, TouchScrollOnAndroidScrollbar) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
}
+TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
+ CommitWithNoPaintWorkletLayerPainter) {
+ ASSERT_FALSE(host_impl_->GetPaintWorkletLayerPainterForTesting());
+ host_impl_->CreatePendingTree();
+
+ // When there is no PaintWorkletLayerPainter registered, commits should finish
+ // immediately and move onto preparing tiles.
+ ASSERT_FALSE(did_prepare_tiles_);
+ host_impl_->CommitComplete();
+ EXPECT_TRUE(did_prepare_tiles_);
+}
+
+TEST_F(CommitToPendingTreeLayerTreeHostImplTest, CommitWithNoPaintWorklets) {
+ host_impl_->SetPaintWorkletLayerPainter(
+ std::make_unique<TestPaintWorkletLayerPainter>());
+ host_impl_->CreatePendingTree();
+
+ // When there are no PaintWorklets in the committed display lists, commits
+ // should finish immediately and move onto preparing tiles.
+ ASSERT_FALSE(did_prepare_tiles_);
+ host_impl_->CommitComplete();
+ EXPECT_TRUE(did_prepare_tiles_);
+}
+
+TEST_F(CommitToPendingTreeLayerTreeHostImplTest, CommitWithDirtyPaintWorklets) {
+ auto painter_owned = std::make_unique<TestPaintWorkletLayerPainter>();
+ TestPaintWorkletLayerPainter* painter = painter_owned.get();
+ host_impl_->SetPaintWorkletLayerPainter(std::move(painter_owned));
+
+ // Setup the pending tree with a PictureLayerImpl that will contain
+ // PaintWorklets.
+ host_impl_->CreatePendingTree();
+ std::unique_ptr<PictureLayerImpl> root_owned = PictureLayerImpl::Create(
+ host_impl_->pending_tree(), 1, Layer::LayerMaskType::NOT_MASK);
+ PictureLayerImpl* root = root_owned.get();
+ host_impl_->pending_tree()->SetRootLayerForTesting(std::move(root_owned));
+
+ root->SetBounds(gfx::Size(100, 100));
+ root->test_properties()->force_render_surface = true;
+ root->SetNeedsPushProperties();
+
+ // Add a PaintWorkletInput to the PictureLayerImpl.
+ scoped_refptr<RasterSource> raster_source_with_pws(
+ FakeRasterSource::CreateFilledWithPaintWorklet(root->bounds()));
+ Region empty_invalidation;
+ root->UpdateRasterSource(raster_source_with_pws, &empty_invalidation, nullptr,
+ nullptr);
+
+ host_impl_->pending_tree()->SetElementIdsForTesting();
+ host_impl_->pending_tree()->BuildPropertyTreesForTesting();
+
+ // Since we have dirty PaintWorklets, committing will not cause tile
+ // preparation to happen. Instead, it will be delayed until the callback
+ // passed to the PaintWorkletLayerPainter is called.
+ did_prepare_tiles_ = false;
+ host_impl_->CommitComplete();
+ EXPECT_FALSE(did_prepare_tiles_);
+
+ // Set up a result to have been 'painted'.
+ ASSERT_EQ(root->GetPaintWorkletRecordMap().size(), 1u);
+ scoped_refptr<PaintWorkletInput> input =
+ root->GetPaintWorkletRecordMap().begin()->first;
+ int worklet_id = input->WorkletId();
+
+ PaintWorkletJob painted_job(worklet_id, input);
+ sk_sp<PaintRecord> record = sk_make_sp<PaintRecord>();
+ painted_job.SetOutput(record);
+
+ auto painted_job_vector = base::MakeRefCounted<PaintWorkletJobVector>();
+ painted_job_vector->data.push_back(std::move(painted_job));
+ PaintWorkletJobMap painted_job_map;
+ painted_job_map[worklet_id] = std::move(painted_job_vector);
+
+ // Finally, 'paint' the content. This should unlock tile preparation and
+ // update the PictureLayerImpl's map.
+ std::move(painter->TakeDoneCallback()).Run(std::move(painted_job_map));
+ EXPECT_EQ(root->GetPaintWorkletRecordMap().find(input)->second, record);
+ EXPECT_TRUE(did_prepare_tiles_);
+}
+
+TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
+ CommitWithNoDirtyPaintWorklets) {
+ host_impl_->SetPaintWorkletLayerPainter(
+ std::make_unique<TestPaintWorkletLayerPainter>());
+
+ host_impl_->CreatePendingTree();
+ std::unique_ptr<PictureLayerImpl> root_owned = PictureLayerImpl::Create(
+ host_impl_->pending_tree(), 1, Layer::LayerMaskType::NOT_MASK);
+ PictureLayerImpl* root = root_owned.get();
+ host_impl_->pending_tree()->SetRootLayerForTesting(std::move(root_owned));
+
+ root->SetBounds(gfx::Size(100, 100));
+ root->test_properties()->force_render_surface = true;
+ root->SetNeedsPushProperties();
+
+ // Add some PaintWorklets.
+ scoped_refptr<RasterSource> raster_source_with_pws(
+ FakeRasterSource::CreateFilledWithPaintWorklet(root->bounds()));
+ Region empty_invalidation;
+ root->UpdateRasterSource(raster_source_with_pws, &empty_invalidation, nullptr,
+ nullptr);
+
+ host_impl_->pending_tree()->SetElementIdsForTesting();
+ host_impl_->pending_tree()->BuildPropertyTreesForTesting();
+
+ // Pretend that our worklets were already painted.
+ ASSERT_EQ(root->GetPaintWorkletRecordMap().size(), 1u);
+ root->SetPaintWorkletRecord(root->GetPaintWorkletRecordMap().begin()->first,
+ sk_make_sp<PaintRecord>());
+
+ // Since there are no dirty PaintWorklets, the commit should immediately
+ // prepare tiles.
+ ASSERT_FALSE(did_prepare_tiles_);
+ host_impl_->CommitComplete();
+ EXPECT_TRUE(did_prepare_tiles_);
+}
+
+class ForceActivateAfterPaintWorkletPaintLayerTreeHostImplTest
+ : public CommitToPendingTreeLayerTreeHostImplTest {
+ public:
+ void NotifyPaintWorkletStateChange(
+ Scheduler::PaintWorkletState state) override {
+ if (state == Scheduler::PaintWorkletState::IDLE) {
+ // Pretend a force activation happened.
+ host_impl_->ActivateSyncTree();
+ ASSERT_FALSE(host_impl_->pending_tree());
+ }
+ }
+};
+
+TEST_F(ForceActivateAfterPaintWorkletPaintLayerTreeHostImplTest,
+ ForceActivationAfterPaintWorkletsFinishPainting) {
+ auto painter_owned = std::make_unique<TestPaintWorkletLayerPainter>();
+ TestPaintWorkletLayerPainter* painter = painter_owned.get();
+ host_impl_->SetPaintWorkletLayerPainter(std::move(painter_owned));
+
+ // Setup the pending tree with a PictureLayerImpl that will contain
+ // PaintWorklets.
+ host_impl_->CreatePendingTree();
+ std::unique_ptr<PictureLayerImpl> root_owned = PictureLayerImpl::Create(
+ host_impl_->pending_tree(), 1, Layer::LayerMaskType::NOT_MASK);
+ PictureLayerImpl* root = root_owned.get();
+ host_impl_->pending_tree()->SetRootLayerForTesting(std::move(root_owned));
+
+ root->SetBounds(gfx::Size(100, 100));
+ root->test_properties()->force_render_surface = true;
+ root->SetNeedsPushProperties();
+
+ // Add a PaintWorkletInput to the PictureLayerImpl.
+ scoped_refptr<RasterSource> raster_source_with_pws(
+ FakeRasterSource::CreateFilledWithPaintWorklet(root->bounds()));
+ Region empty_invalidation;
+ root->UpdateRasterSource(raster_source_with_pws, &empty_invalidation, nullptr,
+ nullptr);
+
+ host_impl_->pending_tree()->SetElementIdsForTesting();
+ host_impl_->pending_tree()->BuildPropertyTreesForTesting();
+
+ // Since we have dirty PaintWorklets, committing will not cause tile
+ // preparation to happen. Instead, it will be delayed until the callback
+ // passed to the PaintWorkletLayerPainter is called.
+ did_prepare_tiles_ = false;
+ host_impl_->CommitComplete();
+ EXPECT_FALSE(did_prepare_tiles_);
+
+ // Set up a result to have been 'painted'.
+ ASSERT_EQ(root->GetPaintWorkletRecordMap().size(), 1u);
+ scoped_refptr<PaintWorkletInput> input =
+ root->GetPaintWorkletRecordMap().begin()->first;
+ int worklet_id = input->WorkletId();
+
+ PaintWorkletJob painted_job(worklet_id, input);
+ sk_sp<PaintRecord> record = sk_make_sp<PaintRecord>();
+ painted_job.SetOutput(record);
+
+ auto painted_job_vector = base::MakeRefCounted<PaintWorkletJobVector>();
+ painted_job_vector->data.push_back(std::move(painted_job));
+ PaintWorkletJobMap painted_job_map;
+ painted_job_map[worklet_id] = std::move(painted_job_vector);
+
+ // Finally, 'paint' the content. The test class causes a forced activation
+ // during NotifyPaintWorkletStateChange. The PictureLayerImpl should still be
+ // updated, but since the tree was force activated there should be no tile
+ // preparation.
+ std::move(painter->TakeDoneCallback()).Run(std::move(painted_job_map));
+ EXPECT_EQ(root->GetPaintWorkletRecordMap().find(input)->second, record);
+ EXPECT_FALSE(did_prepare_tiles_);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_perftest.cc b/chromium/cc/trees/layer_tree_host_perftest.cc
index 92fd3570952..c6036f13f59 100644
--- a/chromium/cc/trees/layer_tree_host_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_perftest.cc
@@ -21,10 +21,10 @@
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/layer_tree_json_parser.h"
#include "cc/test/layer_tree_test.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_impl.h"
#include "components/viz/common/resources/single_release_callback.h"
#include "components/viz/test/paths.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "testing/perf/perf_test.h"
@@ -48,7 +48,7 @@ class LayerTreeHostPerfTest : public LayerTreeTest {
measure_commit_cost_(false) {
}
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -58,7 +58,7 @@ class LayerTreeHostPerfTest : public LayerTreeTest {
bool synchronous_composite =
!HasImplThread() &&
!layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
- return std::make_unique<viz::TestLayerTreeFrameSink>(
+ return std::make_unique<TestLayerTreeFrameSink>(
compositor_context_provider, std::move(worker_context_provider),
gpu_memory_buffer_manager(), renderer_settings, ImplThreadTaskRunner(),
synchronous_composite, disable_display_vsync, refresh_rate);
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
index 3f0c28b4311..7d5ea2a2d08 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -14,7 +14,7 @@
#include "cc/paint/skia_paint_canvas.h"
#include "cc/test/layer_tree_pixel_resource_test.h"
#include "cc/test/pixel_comparator.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -71,7 +71,7 @@ class LayerTreeHostBlendingPixelTest
public:
LayerTreeHostBlendingPixelTest()
: force_antialiasing_(false), force_blending_with_shaders_(false) {
- pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true));
+ pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true);
}
PixelResourceTestCase resource_type() const {
@@ -82,7 +82,7 @@ class LayerTreeHostBlendingPixelTest
}
protected:
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -132,7 +132,7 @@ class LayerTreeHostBlendingPixelTest
gfx::Size bounds = layer->bounds();
scoped_refptr<PictureImageLayer> mask = PictureImageLayer::Create();
mask->SetIsDrawable(true);
- mask->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask->SetLayerMaskType(Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
mask->SetBounds(bounds);
sk_sp<SkSurface> surface =
@@ -213,10 +213,10 @@ class LayerTreeHostBlendingPixelTest
InitializeFromTestCase(resource_type());
// Force shaders only applies to gl renderer.
- if (renderer_type_ != RENDERER_GL && flags & kForceShaders)
+ if (renderer_type() != RENDERER_GL && flags & kForceShaders)
return;
- SCOPED_TRACE(TestTypeToString(renderer_type_));
+ SCOPED_TRACE(TestTypeToString(renderer_type()));
SCOPED_TRACE(SkBlendMode_Name(current_blend_mode()));
scoped_refptr<SolidColorLayer> root = CreateSolidColorLayer(
@@ -229,28 +229,23 @@ class LayerTreeHostBlendingPixelTest
CreateBlendingColorLayers(kRootWidth, kRootHeight, background.get(), flags);
- this->force_antialiasing_ = (flags & kUseAntialiasing);
- this->force_blending_with_shaders_ = (flags & kForceShaders);
+ force_antialiasing_ = (flags & kUseAntialiasing);
+ force_blending_with_shaders_ = (flags & kForceShaders);
- if ((flags & kUseAntialiasing) && (renderer_type_ == RENDERER_GL)) {
+ if ((renderer_type() == RENDERER_GL && force_antialiasing_) ||
+ renderer_type() == RENDERER_SKIA_VK) {
// Blending results might differ with one pixel.
- // Don't allow large errors here, only off by ones.
- // However, large error still has to be specified to satisfy
- // the pixel comparator so set it equivalent to small errors.
+ float percentage_pixels_error = 35.f;
+ float percentage_pixels_small_error = 0.f;
+ float average_error_allowed_in_bad_pixels = 1.f;
int large_error_allowed = 1;
- int small_error_allowed = 1;
- float percentage_pixels_small_error = 35.0f;
- float percentage_pixels_error = 35.0f;
- // The average error is still close to 1.
- float average_error_allowed_in_bad_pixels = 1.4f;
-
- pixel_comparator_.reset(
- new FuzzyPixelComparator(false, // discard_alpha
- percentage_pixels_error,
- percentage_pixels_small_error,
- average_error_allowed_in_bad_pixels,
- large_error_allowed,
- small_error_allowed));
+ int small_error_allowed = 0;
+
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
+ false, // discard_alpha
+ percentage_pixels_error, percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels, large_error_allowed,
+ small_error_allowed);
}
RunPixelResourceTest(root, CreateBlendingWithRenderPassExpected(
@@ -262,19 +257,18 @@ class LayerTreeHostBlendingPixelTest
SkColor misc_opaque_color_ = 0xffc86464;
};
-INSTANTIATE_TEST_SUITE_P(
- B,
- LayerTreeHostBlendingPixelTest,
- ::testing::Combine(::testing::Values(SOFTWARE, ZERO_COPY, SKIA_GL),
- ::testing::ValuesIn(kBlendModes)));
-
-using LayerTreeHostBlendingPixelTestNonSkia = LayerTreeHostBlendingPixelTest;
+std::vector<PixelResourceTestCase> const kTestCases = {
+ {LayerTreeTest::RENDERER_SOFTWARE, SOFTWARE},
+ {LayerTreeTest::RENDERER_GL, ZERO_COPY},
+ {LayerTreeTest::RENDERER_SKIA_GL, GPU},
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ {LayerTreeTest::RENDERER_SKIA_VK, GPU},
+#endif
+};
-// TODO(crbug.com/948128): Enable these tests for Skia.
INSTANTIATE_TEST_SUITE_P(B,
- LayerTreeHostBlendingPixelTestNonSkia,
- ::testing::Combine(::testing::Values(SOFTWARE,
- ZERO_COPY),
+ LayerTreeHostBlendingPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kTestCases),
::testing::ValuesIn(kBlendModes)));
TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithRoot) {
@@ -304,7 +298,7 @@ TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithRoot) {
RunPixelResourceTest(background, expected);
}
-TEST_P(LayerTreeHostBlendingPixelTestNonSkia, BlendingWithBackdropFilter) {
+TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithBackdropFilter) {
const int kRootWidth = 2;
const int kRootHeight = 2;
InitializeFromTestCase(resource_type());
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
index 165f1d8879c..3ac848ed527 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -4,6 +4,7 @@
#include <stddef.h>
+#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "cc/layers/picture_layer.h"
#include "cc/layers/solid_color_layer.h"
@@ -21,14 +22,6 @@ class LayerTreeHostFiltersPixelTest
: public LayerTreePixelTest,
public ::testing::WithParamInterface<LayerTreeTest::RendererType> {
protected:
- void InitializeSettings(LayerTreeSettings* settings) override {
- LayerTreePixelTest::InitializeSettings(settings);
- // Required so that device scale is inherited by content scale. True for
- // most tests, but can be overwritten before RunPixelTest() is called.
- settings->layer_transforms_should_scale_layer_contents =
- layer_transforms_should_scale_layer_contents_;
- }
-
RendererType renderer_type() { return GetParam(); }
// Text string for graphics backend of the RendererType. Suitable for
@@ -38,7 +31,9 @@ class LayerTreeHostFiltersPixelTest
case RENDERER_GL:
return "gl";
case RENDERER_SKIA_GL:
- return "skia";
+ return "skia_gl";
+ case RENDERER_SKIA_VK:
+ return "skia_vk";
case RENDERER_SOFTWARE:
return "sw";
}
@@ -71,23 +66,20 @@ class LayerTreeHostFiltersPixelTest
return background;
}
+};
- bool layer_transforms_should_scale_layer_contents_ = true;
+LayerTreeTest::RendererType const kRendererTypes[] = {
+ LayerTreeTest::RENDERER_GL,
+ LayerTreeTest::RENDERER_SKIA_GL,
+ LayerTreeTest::RENDERER_SOFTWARE,
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ LayerTreeTest::RENDERER_SKIA_VK,
+#endif
};
INSTANTIATE_TEST_SUITE_P(,
LayerTreeHostFiltersPixelTest,
- ::testing::Values(LayerTreeTest::RENDERER_GL,
- LayerTreeTest::RENDERER_SKIA_GL,
- LayerTreeTest::RENDERER_SOFTWARE));
-
-using LayerTreeHostFiltersPixelTestNonSkia = LayerTreeHostFiltersPixelTest;
-
-// TODO(crbug.com/948128): Enable these tests for Skia.
-INSTANTIATE_TEST_SUITE_P(,
- LayerTreeHostFiltersPixelTestNonSkia,
- ::testing::Values(LayerTreeTest::RENDERER_GL,
- LayerTreeTest::RENDERER_SOFTWARE));
+ ::testing::ValuesIn(kRendererTypes));
using LayerTreeHostFiltersPixelTestGL = LayerTreeHostFiltersPixelTest;
@@ -98,12 +90,19 @@ INSTANTIATE_TEST_SUITE_P(,
using LayerTreeHostFiltersPixelTestGPU = LayerTreeHostFiltersPixelTest;
+LayerTreeTest::RendererType const kRendererTypesGpu[] = {
+ LayerTreeTest::RENDERER_GL,
+ LayerTreeTest::RENDERER_SKIA_GL,
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ LayerTreeTest::RENDERER_SKIA_VK,
+#endif
+};
+
INSTANTIATE_TEST_SUITE_P(,
LayerTreeHostFiltersPixelTestGPU,
- ::testing::Values(LayerTreeTest::RENDERER_GL,
- LayerTreeTest::RENDERER_SKIA_GL));
+ ::testing::ValuesIn(kRendererTypesGpu));
-TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurRect) {
+TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRect) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
@@ -139,11 +138,56 @@ TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurRect) {
small_error_allowed));
#endif
- RunPixelTest(renderer_type(), background,
- base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur.png")));
+ RunPixelTest(
+ renderer_type(), background,
+ (renderer_type() == RENDERER_SOFTWARE)
+ ? base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur_sw.png"))
+ : base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur.png")));
+}
+
+TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRadius) {
+ if (renderer_type() == RENDERER_SOFTWARE) {
+ // TODO(989238): Software renderer does not support/implement
+ // kClamp_TileMode.
+ return;
+ }
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorRED);
+ scoped_refptr<SolidColorLayer> green =
+ CreateSolidColorLayer(gfx::Rect(200, 200, 200, 200), kCSSLime);
+ gfx::Rect blur_rect(100, 100, 200, 200);
+ scoped_refptr<SolidColorLayer> blur =
+ CreateSolidColorLayer(blur_rect, SkColorSetARGB(40, 10, 20, 200));
+ background->AddChild(green);
+ background->AddChild(blur);
+
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateBlurFilter(
+ 30.f, SkBlurImageFilter::kClamp_TileMode));
+ blur->SetBackdropFilters(filters);
+ gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())), 0);
+ blur->SetBackdropFilterBounds(backdrop_filter_bounds);
+
+#if defined(OS_WIN) || defined(ARCH_CPU_ARM64)
+ // Windows and ARM64 have 436 pixels off by 1: crbug.com/259915
+ float percentage_pixels_large_error = 1.09f; // 436px / (200*200)
+ float percentage_pixels_small_error = 0.0f;
+ float average_error_allowed_in_bad_pixels = 1.f;
+ int large_error_allowed = 1;
+ int small_error_allowed = 0;
+ pixel_comparator_.reset(new FuzzyPixelComparator(
+ true, // discard_alpha
+ percentage_pixels_large_error, percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels, large_error_allowed,
+ small_error_allowed));
+#endif
+ RunPixelTest(
+ renderer_type(), background,
+ base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur_radius_.png"))
+ .InsertBeforeExtensionASCII(GetRendererSuffix()));
}
-TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurRounded) {
+TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRounded) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -180,17 +224,17 @@ TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurRounded) {
pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(false);
#endif
- RunPixelTest(
- renderer_type(), background,
- base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur_rounded.png")));
+ RunPixelTest(renderer_type(), background,
+ (renderer_type() == RENDERER_SOFTWARE)
+ ? base::FilePath(FILE_PATH_LITERAL(
+ "backdrop_filter_blur_rounded_sw.png"))
+ : base::FilePath(FILE_PATH_LITERAL(
+ "backdrop_filter_blur_rounded.png")));
}
-TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurOutsets) {
- if (renderer_type() == RENDERER_SKIA_GL
-#if defined(ENABLE_CC_VULKAN_TESTS)
- || renderer_type() == RENDERER_SKIA_VK
-#endif
- ) {
+TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurOutsets) {
+ if (renderer_type() == RENDERER_SKIA_GL ||
+ renderer_type() == RENDERER_SKIA_VK) {
// TODO(973696): Implement bounds clipping in skia_renderer.
return;
}
@@ -233,6 +277,9 @@ TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurOutsets) {
average_error_allowed_in_bad_pixels,
large_error_allowed,
small_error_allowed));
+#else
+ if (renderer_type() == RENDERER_SKIA_VK)
+ pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true);
#endif
RunPixelTest(
@@ -380,9 +427,7 @@ class LayerTreeHostFiltersScaledPixelTest
INSTANTIATE_TEST_SUITE_P(,
LayerTreeHostFiltersScaledPixelTest,
- ::testing::Values(LayerTreeTest::RENDERER_GL,
- LayerTreeTest::RENDERER_SKIA_GL,
- LayerTreeTest::RENDERER_SOFTWARE));
+ ::testing::ValuesIn(kRendererTypes));
TEST_P(LayerTreeHostFiltersScaledPixelTest, StandardDpi) {
RunPixelTestType(100, 1.f);
@@ -393,8 +438,6 @@ TEST_P(LayerTreeHostFiltersScaledPixelTest, HiDpi) {
}
TEST_P(LayerTreeHostFiltersPixelTest, NullFilter) {
- layer_transforms_should_scale_layer_contents_ = false;
-
scoped_refptr<SolidColorLayer> foreground =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorGREEN);
@@ -407,8 +450,6 @@ TEST_P(LayerTreeHostFiltersPixelTest, NullFilter) {
}
TEST_P(LayerTreeHostFiltersPixelTest, CroppedFilter) {
- layer_transforms_should_scale_layer_contents_ = false;
-
scoped_refptr<SolidColorLayer> foreground =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorGREEN);
@@ -668,7 +709,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageRenderSurfaceScaled) {
.InsertBeforeExtensionASCII(GetRendererSuffix()));
}
-TEST_P(LayerTreeHostFiltersPixelTestNonSkia, ZoomFilter) {
+TEST_P(LayerTreeHostFiltersPixelTest, ZoomFilter) {
scoped_refptr<SolidColorLayer> root =
CreateSolidColorLayer(gfx::Rect(300, 300), SK_ColorWHITE);
@@ -945,8 +986,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, EnlargedTextureWithCropOffsetFilter) {
base::FilePath(FILE_PATH_LITERAL("enlarged_texture_on_crop_offset.png")));
}
-// TODO(crbug.com/948128): Enable this test for SkiaRenderer.
-TEST_P(LayerTreeHostFiltersPixelTestNonSkia, BlurFilterWithClip) {
+TEST_P(LayerTreeHostFiltersPixelTest, BlurFilterWithClip) {
scoped_refptr<SolidColorLayer> child1 =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLUE);
scoped_refptr<SolidColorLayer> child2 =
@@ -1010,32 +1050,96 @@ TEST_P(LayerTreeHostFiltersPixelTestGPU, FilterWithGiantCropRectNoClip) {
base::FilePath(FILE_PATH_LITERAL("filter_with_giant_crop_rect.png")));
}
-class BackdropFilterWithDeviceScaleFactorTest
- : public LayerTreeHostFiltersPixelTest {
+class BackdropFilterOffsetTest : public LayerTreeHostFiltersPixelTest {
protected:
- void RunPixelTestType(float device_scale_factor,
- const base::FilePath& expected_result) {
- device_scale_factor_ = device_scale_factor;
-
+ void RunPixelTestType(int device_scale_factor) {
scoped_refptr<Layer> root =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(100, 120), SK_ColorBLACK);
root->AddChild(background);
-
scoped_refptr<SolidColorLayer> filtered = CreateSolidColorLayer(
gfx::Rect(0, 100, 200, 100), SkColorSetA(SK_ColorGREEN, 127));
FilterOperations filters;
+ // TODO(989329): This test actually also tests how the OffsetPaintFilter
+ // handles the edge condition. Because the OffsetPaintFilter is pulling
+ // content from outside the filter region (just the bottom 200x100 square),
+ // it must create content for all but the bottom 20px of the filter rect.
+ // The GPU implementation of OffsetPaintFilter effectively clamps to the
+ // edge pixels and copies them into the top 80px of the image. The CPU
+ // implementation, on the other hand, pulls in transparent pixels for those
+ // 80px. The behavior is basically unspecified, though for blur filters the
+ // explicitly specified behavior is edgemode:duplicate, as seen in [1]. And
+ // the default for svg filters, including feOffset, is also duplicate.
+ // [1] https://drafts.fxtf.org/filter-effects-2/#backdrop-filter-operation
+ // [2] https://www.w3.org/TR/SVG11/filters.html#feConvolveMatrixElementEdgeModeAttribute
filters.Append(FilterOperation::CreateReferenceFilter(
sk_make_sp<OffsetPaintFilter>(0, 80, nullptr)));
filtered->SetBackdropFilters(filters);
filtered->ClearBackdropFilterBounds();
root->AddChild(filtered);
-
// This should appear as a grid of 4 100x100 squares which are:
// BLACK WHITE
- // DARK GREEN LIGHT GREEN
+ // DARK GREEN* LIGHT GREEN
+ //
+ // *except for software (see crbug.com/989329) which will be a
+ // dark-light-dark horizontal sandwich.
+ device_scale_factor_ = device_scale_factor;
+
+ base::FilePath expected_result =
+ base::FilePath(FILE_PATH_LITERAL("offset_backdrop_filter_.png"));
+ expected_result = expected_result.InsertBeforeExtensionASCII(
+ base::NumberToString(device_scale_factor) + "x");
+ if (renderer_type() == RENDERER_SOFTWARE) {
+ expected_result = expected_result.InsertBeforeExtensionASCII("_sw");
+ }
+ RunPixelTest(renderer_type(), std::move(root), expected_result);
+ }
+
+ private:
+ // LayerTreePixelTest overrides
+ void SetupTree() override {
+ SetInitialDeviceScaleFactor(device_scale_factor_);
+ LayerTreeHostFiltersPixelTest::SetupTree();
+ }
+
+ float device_scale_factor_ = 1;
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+ BackdropFilterOffsetTest,
+ ::testing::ValuesIn(kRendererTypes));
+
+TEST_P(BackdropFilterOffsetTest, StandardDpi) {
+ RunPixelTestType(1.f);
+}
+
+TEST_P(BackdropFilterOffsetTest, HiDpi) {
+ RunPixelTestType(2.f);
+}
+
+class BackdropFilterInvertTest : public LayerTreeHostFiltersPixelTest {
+ protected:
+ void RunPixelTestType(int device_scale_factor) {
+ scoped_refptr<Layer> root =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+ scoped_refptr<SolidColorLayer> filtered =
+ CreateSolidColorLayer(gfx::Rect(50, 50, 100, 100), SK_ColorTRANSPARENT);
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateInvertFilter(1.0));
+ filtered->SetBackdropFilters(filters);
+ gfx::RRectF backdrop_filter_bounds(
+ gfx::RectF(gfx::SizeF(filtered->bounds())), 20);
+ filtered->SetBackdropFilterBounds(backdrop_filter_bounds);
+ root->AddChild(filtered);
+ device_scale_factor_ = device_scale_factor;
+ base::FilePath expected_result =
+ base::FilePath(FILE_PATH_LITERAL("invert_backdrop_filter_.png"));
+ expected_result = expected_result.InsertBeforeExtensionASCII(
+ base::NumberToString(device_scale_factor) + "x");
+ if (renderer_type() == RENDERER_SOFTWARE) {
+ expected_result = expected_result.InsertBeforeExtensionASCII("_sw");
+ }
RunPixelTest(renderer_type(), std::move(root), expected_result);
}
@@ -1049,21 +1153,16 @@ class BackdropFilterWithDeviceScaleFactorTest
float device_scale_factor_ = 1;
};
-// TODO(973699): This test is broken in software_renderer. Re-enable this test
-// when fixed.
INSTANTIATE_TEST_SUITE_P(,
- BackdropFilterWithDeviceScaleFactorTest,
- ::testing::Values(LayerTreeTest::RENDERER_GL,
- LayerTreeTest::RENDERER_SKIA_GL));
+ BackdropFilterInvertTest,
+ ::testing::ValuesIn(kRendererTypes));
-TEST_P(BackdropFilterWithDeviceScaleFactorTest, StandardDpi) {
- RunPixelTestType(
- 1.f, base::FilePath(FILE_PATH_LITERAL("offset_backdrop_filter_1x.png")));
+TEST_P(BackdropFilterInvertTest, StandardDpi) {
+ RunPixelTestType(1.f);
}
-TEST_P(BackdropFilterWithDeviceScaleFactorTest, HiDpi) {
- RunPixelTestType(
- 2.f, base::FilePath(FILE_PATH_LITERAL("offset_backdrop_filter_2x.png")));
+TEST_P(BackdropFilterInvertTest, HiDpi) {
+ RunPixelTestType(2.f);
}
} // namespace
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
index 9e125057e0d..1dcc664c201 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -18,7 +18,7 @@
#include "cc/test/layer_tree_pixel_resource_test.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/solid_color_content_layer_client.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "third_party/skia/include/core/SkImage.h"
#if !defined(OS_ANDROID)
@@ -26,9 +26,33 @@
namespace cc {
namespace {
+auto CombineWithLayerMaskTypes(
+ const std::vector<PixelResourceTestCase>& test_cases) {
+ return ::testing::Combine(
+ ::testing::ValuesIn(test_cases),
+ ::testing::Values(Layer::LayerMaskType::SINGLE_TEXTURE_MASK));
+}
+
+// TODO(penghuang): Fix vulkan with one copy or zero copy
+// https://crbug.com/979703
+std::vector<PixelResourceTestCase> const kTestCases = {
+ {LayerTreeTest::RENDERER_SOFTWARE, SOFTWARE},
+ {LayerTreeTest::RENDERER_GL, GPU},
+ {LayerTreeTest::RENDERER_GL, ONE_COPY},
+ {LayerTreeTest::RENDERER_GL, ZERO_COPY},
+ {LayerTreeTest::RENDERER_SKIA_GL, GPU},
+ {LayerTreeTest::RENDERER_SKIA_GL, ONE_COPY},
+ {LayerTreeTest::RENDERER_SKIA_GL, ZERO_COPY},
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ {LayerTreeTest::RENDERER_SKIA_VK, GPU},
+#endif
+};
+
using LayerTreeHostMasksPixelTest = ParameterizedPixelResourceTest;
-INSTANTIATE_PIXEL_RESOURCE_TEST_SUITE_P(LayerTreeHostMasksPixelTest);
+INSTANTIATE_TEST_SUITE_P(PixelResourceTest,
+ LayerTreeHostMasksPixelTest,
+ CombineWithLayerMaskTypes(kTestCases));
class MaskContentLayerClient : public ContentLayerClient {
public:
@@ -89,17 +113,23 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfLayer) {
mask->SetLayerMaskType(mask_type_);
green->SetMaskLayer(mask.get());
+ pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true);
+
RunPixelResourceTest(background,
base::FilePath(FILE_PATH_LITERAL("mask_of_layer.png")));
}
class LayerTreeHostLayerListPixelTest : public ParameterizedPixelResourceTest {
+ protected:
void InitializeSettings(LayerTreeSettings* settings) override {
settings->use_layer_lists = true;
+ settings->gpu_rasterization_forced = use_vulkan();
}
};
-INSTANTIATE_PIXEL_RESOURCE_TEST_SUITE_P(LayerTreeHostLayerListPixelTest);
+INSTANTIATE_TEST_SUITE_P(PixelResourceTest,
+ LayerTreeHostLayerListPixelTest,
+ CombineWithLayerMaskTypes(kTestCases));
TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffect) {
PropertyTrees property_trees;
@@ -153,6 +183,9 @@ TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffect) {
mask->SetTransformTreeIndex(1);
root_layer->AddChild(mask);
+ pixel_comparator_ =
+ std::make_unique<FuzzyPixelOffByOneComparator>(true /* discard_alpha */);
+
RunPixelResourceTestWithLayerList(
root_layer, base::FilePath(FILE_PATH_LITERAL("mask_with_effect.png")),
&property_trees);
@@ -418,18 +451,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffectNoContentToMask) {
&property_trees);
}
-using LayerTreeHostLayerListPixelTestNonSkia = LayerTreeHostLayerListPixelTest;
-
-// TODO(crbug.com/948128): Enable this test for Skia.
-INSTANTIATE_TEST_SUITE_P(
- PixelResourceTest,
- LayerTreeHostLayerListPixelTestNonSkia,
- ::testing::Combine(
- ::testing::Values(SOFTWARE, GPU, ONE_COPY, ZERO_COPY),
- ::testing::Values(Layer::LayerMaskType::SINGLE_TEXTURE_MASK,
- Layer::LayerMaskType::MULTI_TEXTURE_MASK)));
-
-TEST_P(LayerTreeHostLayerListPixelTestNonSkia, ScaledMaskWithEffect) {
+TEST_P(LayerTreeHostLayerListPixelTest, ScaledMaskWithEffect) {
PropertyTrees property_trees;
scoped_refptr<Layer> root_layer;
InitializeForLayerListMode(&root_layer, &property_trees);
@@ -450,10 +472,12 @@ TEST_P(LayerTreeHostLayerListPixelTestNonSkia, ScaledMaskWithEffect) {
// Scale the mask with a non-integral transform. This will trigger the
// AA path in the renderer.
- TransformNode transform;
- transform.local = gfx::Transform();
- transform.local.Scale(1.5, 1.5);
- property_trees.transform_tree.Insert(transform, 1);
+ TransformTree& transform_tree = property_trees.transform_tree;
+ auto& transform_node =
+ *transform_tree.Node(transform_tree.Insert(TransformNode(), 1));
+ transform_node.source_node_id = transform_node.parent_id;
+ transform_node.local = gfx::Transform();
+ transform_node.local.Scale(1.5, 1.5);
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
@@ -488,20 +512,13 @@ TEST_P(LayerTreeHostLayerListPixelTestNonSkia, ScaledMaskWithEffect) {
mask->SetTransformTreeIndex(2);
root_layer->AddChild(mask);
- float percentage_pixels_large_error = 2.5f; // 2.5%, ~250px / (100*100)
- float percentage_pixels_small_error = 0.0f;
- float average_error_allowed_in_bad_pixels = 100.0f;
- int large_error_allowed = 256;
- int small_error_allowed = 0;
- pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
- true, // discard_alpha
- percentage_pixels_large_error, percentage_pixels_small_error,
- average_error_allowed_in_bad_pixels, large_error_allowed,
- small_error_allowed);
+ pixel_comparator_ =
+ std::make_unique<FuzzyPixelOffByOneComparator>(true /* discard_alpha */);
RunPixelResourceTestWithLayerList(
root_layer,
- base::FilePath(FILE_PATH_LITERAL("scaled_mask_with_effect.png")),
+ base::FilePath(FILE_PATH_LITERAL("scaled_mask_with_effect_.png"))
+ .InsertBeforeExtensionASCII(GetRendererSuffix()),
&property_trees);
}
@@ -557,6 +574,9 @@ TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffectDifferentSize) {
mask->SetTransformTreeIndex(1);
root_layer->AddChild(mask);
+ pixel_comparator_ =
+ std::make_unique<FuzzyPixelOffByOneComparator>(true /* discard_alpha */);
+
// The mask is half the size of thing it's masking. In layer-list mode,
// the mask is not automatically scaled to match the other layer.
RunPixelResourceTestWithLayerList(
@@ -631,6 +651,9 @@ TEST_P(LayerTreeHostLayerListPixelTest, ImageMaskWithEffect) {
SkMatrix::I(), false);
root_layer->AddChild(mask);
+ pixel_comparator_ =
+ std::make_unique<FuzzyPixelOffByOneComparator>(true /* discard_alpha */);
+
// The mask is half the size of thing it's masking. In layer-list mode,
// the mask is not automatically scaled to match the other layer.
RunPixelResourceTestWithLayerList(
@@ -670,6 +693,9 @@ TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
green->SetMaskLayer(mask.get());
background->AddChild(green);
+ pixel_comparator_ =
+ std::make_unique<FuzzyPixelOffByOneComparator>(true /* discard_alpha */);
+
RunPixelResourceTest(
background, base::FilePath(FILE_PATH_LITERAL("image_mask_of_layer.png")));
}
@@ -697,6 +723,9 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfClippedLayer) {
mask->SetLayerMaskType(mask_type_);
green->SetMaskLayer(mask.get());
+ pixel_comparator_ =
+ std::make_unique<FuzzyPixelOffByOneComparator>(true /* discard_alpha */);
+
RunPixelResourceTest(
background,
base::FilePath(FILE_PATH_LITERAL("mask_of_clipped_layer.png")));
@@ -719,6 +748,9 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfLayerNonExactTextureSize) {
mask->set_fixed_tile_size(gfx::Size(173, 135));
green->SetMaskLayer(mask.get());
+ pixel_comparator_ =
+ std::make_unique<FuzzyPixelOffByOneComparator>(true /* discard_alpha */);
+
RunPixelResourceTest(background,
base::FilePath(FILE_PATH_LITERAL(
"mask_with_non_exact_texture_size.png")));
@@ -817,20 +849,9 @@ class CircleContentLayerClient : public ContentLayerClient {
using LayerTreeHostMasksForBackdropFiltersPixelTest =
ParameterizedPixelResourceTest;
-INSTANTIATE_PIXEL_RESOURCE_TEST_SUITE_P(
- LayerTreeHostMasksForBackdropFiltersPixelTest);
-
-using LayerTreeHostMasksForBackdropFiltersPixelTestNonSkia =
- ParameterizedPixelResourceTest;
-
-// TODO(crbug.com/948128): Enable these tests for Skia.
-INSTANTIATE_TEST_SUITE_P(
- PixelResourceTest,
- LayerTreeHostMasksForBackdropFiltersPixelTestNonSkia,
- ::testing::Combine(
- ::testing::Values(SOFTWARE, GPU, ONE_COPY, ZERO_COPY),
- ::testing::Values(Layer::LayerMaskType::SINGLE_TEXTURE_MASK,
- Layer::LayerMaskType::MULTI_TEXTURE_MASK)));
+INSTANTIATE_TEST_SUITE_P(PixelResourceTest,
+ LayerTreeHostMasksForBackdropFiltersPixelTest,
+ CombineWithLayerMaskTypes(kTestCases));
TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest,
MaskOfLayerWithBackdropFilter) {
@@ -863,9 +884,24 @@ TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest,
CHECK_EQ(Layer::LayerMaskType::SINGLE_TEXTURE_MASK, mask->mask_type());
base::FilePath image_name =
- (test_case_ == GPU || test_case_ == SKIA_GL)
+ (raster_type() == GPU)
? base::FilePath(FILE_PATH_LITERAL("mask_of_backdrop_filter_gpu.png"))
: base::FilePath(FILE_PATH_LITERAL("mask_of_backdrop_filter.png"));
+
+ if (renderer_type() == RENDERER_SKIA_VK && raster_type() == GPU) {
+ // Vulkan with GPU raster has 4 pixels errors (the circle mask shape is
+ // slight different).
+ float percentage_pixels_large_error = 0.04f; // 4px / (100*100)
+ float percentage_pixels_small_error = 0.0f;
+ float average_error_allowed_in_bad_pixels = 182.f;
+ int large_error_allowed = 182;
+ int small_error_allowed = 0;
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
+ true /* discard_alpha */, percentage_pixels_large_error,
+ percentage_pixels_small_error, average_error_allowed_in_bad_pixels,
+ large_error_allowed, small_error_allowed);
+ }
+
RunPixelResourceTest(background, image_name);
}
@@ -962,22 +998,16 @@ class LayerTreeHostMaskAsBlendingPixelTest
Layer::LayerMaskType::SINGLE_TEXTURE_MASK),
use_antialiasing_(GetParam().flags & kUseAntialiasing),
force_shaders_(GetParam().flags & kForceShaders) {
- float percentage_pixels_small_error = 0.f;
float percentage_pixels_error = 0.f;
+ float percentage_pixels_small_error = 0.f;
float average_error_allowed_in_bad_pixels = 0.f;
int large_error_allowed = 0;
int small_error_allowed = 0;
- if (use_antialiasing_) {
- percentage_pixels_small_error = 0.9f;
- percentage_pixels_error = 6.7f;
- average_error_allowed_in_bad_pixels = 3.5f;
- large_error_allowed = 15;
- small_error_allowed = 1;
- } else if (test_case_ != SOFTWARE) {
- percentage_pixels_small_error = 0.9f;
- percentage_pixels_error = 6.5f;
- average_error_allowed_in_bad_pixels = 3.5f;
- large_error_allowed = 15;
+ if (renderer_type() != RENDERER_SOFTWARE) {
+ percentage_pixels_error = 6.0f;
+ percentage_pixels_small_error = 2.f;
+ average_error_allowed_in_bad_pixels = 2.1f;
+ large_error_allowed = 11;
small_error_allowed = 1;
} else {
#if defined(ARCH_CPU_ARM64)
@@ -1061,7 +1091,7 @@ class LayerTreeHostMaskAsBlendingPixelTest
}
protected:
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -1080,13 +1110,21 @@ class LayerTreeHostMaskAsBlendingPixelTest
bool force_shaders_;
};
-// TODO(crbug.com/948128): Enable these tests for Skia.
MaskTestConfig const kTestConfigs[] = {
- MaskTestConfig{SOFTWARE, 0},
- MaskTestConfig{ZERO_COPY, 0},
- MaskTestConfig{ZERO_COPY, kUseAntialiasing},
- MaskTestConfig{ZERO_COPY, kForceShaders},
- MaskTestConfig{ZERO_COPY, kUseAntialiasing | kForceShaders},
+ MaskTestConfig{{LayerTreeTest::RENDERER_SOFTWARE, SOFTWARE}, 0},
+ MaskTestConfig{{LayerTreeTest::RENDERER_GL, ZERO_COPY}, 0},
+ MaskTestConfig{{LayerTreeTest::RENDERER_GL, ZERO_COPY}, kUseAntialiasing},
+ MaskTestConfig{{LayerTreeTest::RENDERER_GL, ZERO_COPY}, kForceShaders},
+ MaskTestConfig{{LayerTreeTest::RENDERER_GL, ZERO_COPY},
+ kUseAntialiasing | kForceShaders},
+ MaskTestConfig{{LayerTreeTest::RENDERER_SKIA_GL, ZERO_COPY}, 0},
+ MaskTestConfig{{LayerTreeTest::RENDERER_SKIA_GL, ZERO_COPY},
+ kUseAntialiasing},
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ MaskTestConfig{{LayerTreeTest::RENDERER_SKIA_VK, ZERO_COPY}, 0},
+ MaskTestConfig{{LayerTreeTest::RENDERER_SKIA_VK, ZERO_COPY},
+ kUseAntialiasing},
+#endif
};
INSTANTIATE_TEST_SUITE_P(All,
@@ -1229,7 +1267,7 @@ TEST_P(LayerTreeHostMaskAsBlendingPixelTest, RotatedClippedCircle) {
mask_isolation->AddChild(mask_layer);
base::FilePath image_name =
- (test_case_ == SOFTWARE)
+ (raster_type() == SOFTWARE)
? base::FilePath(
FILE_PATH_LITERAL("mask_as_blending_rotated_circle.png"))
: base::FilePath(
@@ -1276,7 +1314,7 @@ TEST_P(LayerTreeHostMaskAsBlendingPixelTest, RotatedClippedCircleUnderflow) {
mask_isolation->AddChild(mask_layer);
base::FilePath image_name =
- (test_case_ == SOFTWARE)
+ (raster_type() == SOFTWARE)
? base::FilePath(FILE_PATH_LITERAL(
"mask_as_blending_rotated_circle_underflow.png"))
: base::FilePath(FILE_PATH_LITERAL(
@@ -1284,7 +1322,7 @@ TEST_P(LayerTreeHostMaskAsBlendingPixelTest, RotatedClippedCircleUnderflow) {
RunPixelResourceTest(root, image_name);
}
-TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTestNonSkia,
+TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest,
MaskOfLayerWithBackdropFilterAndBlend) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(128, 128), SK_ColorWHITE);
@@ -1322,20 +1360,14 @@ TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTestNonSkia,
mask->SetLayerMaskType(mask_type_);
picture_horizontal->SetMaskLayer(mask.get());
- float percentage_pixels_large_error = 0.062f; // 0.062%, ~10px / (128*128)
- float percentage_pixels_small_error = 0.0f;
- float average_error_allowed_in_bad_pixels = 200.0f;
- int large_error_allowed = 256;
- int small_error_allowed = 0;
- pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
- true, // discard_alpha
- percentage_pixels_large_error, percentage_pixels_small_error,
- average_error_allowed_in_bad_pixels, large_error_allowed,
- small_error_allowed);
-
- RunPixelResourceTest(background,
- base::FilePath(FILE_PATH_LITERAL(
- "mask_of_backdrop_filter_and_blend.png")));
+ base::FilePath result_path(
+ FILE_PATH_LITERAL("mask_of_backdrop_filter_and_blend_.png"));
+ if (raster_type() != GPU) {
+ result_path = result_path.InsertBeforeExtensionASCII("sw");
+ } else {
+ result_path = result_path.InsertBeforeExtensionASCII(GetRendererSuffix());
+ }
+ RunPixelResourceTest(background, result_path);
}
} // namespace
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_mirror.cc b/chromium/cc/trees/layer_tree_host_pixeltest_mirror.cc
new file mode 100644
index 00000000000..ed011f43887
--- /dev/null
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_mirror.cc
@@ -0,0 +1,83 @@
+// Copyright 2019 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 "build/build_config.h"
+#include "cc/layers/mirror_layer.h"
+#include "cc/layers/solid_color_layer.h"
+#include "cc/test/layer_tree_pixel_test.h"
+#include "cc/test/pixel_comparator.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/transform_util.h"
+
+#if !defined(OS_ANDROID)
+
+namespace cc {
+namespace {
+
+class LayerTreeHostMirrorPixelTest
+ : public LayerTreePixelTest,
+ public ::testing::WithParamInterface<LayerTreeTest::RendererType> {
+ protected:
+ RendererType renderer_type() { return GetParam(); }
+};
+
+const LayerTreeTest::RendererType kRendererTypes[] = {
+ LayerTreeTest::RENDERER_GL,
+ LayerTreeTest::RENDERER_SKIA_GL,
+ LayerTreeTest::RENDERER_SOFTWARE,
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ LayerTreeTest::RENDERER_SKIA_VK,
+#endif
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+ LayerTreeHostMirrorPixelTest,
+ ::testing::ValuesIn(kRendererTypes));
+
+// Verifies that a mirror layer with a scale mirrors another layer correctly.
+TEST_P(LayerTreeHostMirrorPixelTest, MirrorLayer) {
+ const float scale = 2.f;
+ gfx::Rect background_bounds(120, 180);
+ gfx::Rect mirrored_bounds(10, 10, 50, 50);
+ gfx::Rect mirror_bounds(10, 70, 100, 100);
+
+ auto background = CreateSolidColorLayer(background_bounds, SK_ColorWHITE);
+
+ auto mirrored_layer = CreateSolidColorLayerWithBorder(
+ mirrored_bounds, SK_ColorGREEN, 5, SK_ColorBLUE);
+
+ auto mirror_layer = MirrorLayer::Create(mirrored_layer);
+ mirror_layer->SetIsDrawable(true);
+ mirror_layer->SetBounds(mirror_bounds.size());
+ mirror_layer->SetPosition(gfx::PointF(mirror_bounds.origin()));
+ mirror_layer->SetTransform(gfx::GetScaleTransform(gfx::Point(), scale));
+ background->AddChild(mirrored_layer);
+ background->AddChild(mirror_layer);
+
+ if (renderer_type() == RENDERER_SOFTWARE) {
+ const bool discard_alpha = true;
+ const float error_pixels_percentage_limit = 3.f;
+ const float small_error_pixels_percentage_limit = 0.f;
+ const float avg_abs_error_limit = 65.f;
+ const int max_abs_error_limit = 120;
+ const int small_error_threshold = 0;
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
+ discard_alpha, error_pixels_percentage_limit,
+ small_error_pixels_percentage_limit, avg_abs_error_limit,
+ max_abs_error_limit, small_error_threshold);
+ }
+
+#if defined(ENABLE_CC_VULKAN_TESTS) && defined(OS_LINUX)
+ if (renderer_type() == RENDERER_SKIA_VK)
+ pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true);
+#endif
+
+ RunPixelTest(renderer_type(), background,
+ base::FilePath(FILE_PATH_LITERAL("mirror_layer.png")));
+}
+
+} // namespace
+} // namespace cc
+
+#endif // !defined(OS_ANDROID)
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
index 41660e1fb34..52317bb5fa2 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
@@ -10,11 +10,11 @@
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/layer_tree_pixel_test.h"
#include "cc/test/solid_color_content_layer_client.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_impl.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/test/paths.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
#if !defined(OS_ANDROID)
@@ -29,9 +29,6 @@ enum ReadbackType {
};
struct ReadbackTestConfig {
- ReadbackTestConfig(LayerTreeTest::RendererType renderer_type_,
- ReadbackType readback_type_)
- : renderer_type(renderer_type_), readback_type(readback_type_) {}
LayerTreeTest::RendererType renderer_type;
ReadbackType readback_type;
};
@@ -191,7 +188,11 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild) {
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubtreeSurroundsTargetLayer) {
+using LayerTreeHostReadbackPixelTestMaybeVulkan =
+ LayerTreeHostReadbackPixelTest;
+
+TEST_P(LayerTreeHostReadbackPixelTestMaybeVulkan,
+ ReadbackSubtreeSurroundsTargetLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
@@ -379,7 +380,7 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerOutsideViewport) {
base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
}
-TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootOrFirstLayer) {
+TEST_P(LayerTreeHostReadbackPixelTestMaybeVulkan, ReadbackNonRootOrFirstLayer) {
// This test has 3 render passes with the copy request on the render pass in
// the middle. This test caught an issue where copy requests on non-root
// non-first render passes were being treated differently from the first
@@ -415,15 +416,40 @@ TEST_P(LayerTreeHostReadbackPixelTest, MultipleReadbacksOnLayer) {
base::FilePath(FILE_PATH_LITERAL("green.png")));
}
-INSTANTIATE_TEST_SUITE_P(
- ,
- LayerTreeHostReadbackPixelTest,
- ::testing::Values(
- ReadbackTestConfig(LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP),
- ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_TEXTURE),
- ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_BITMAP),
- ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP),
- ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE)));
+// TODO(crbug.com/963446): Enable these tests for Skia Vulkan using texture
+// readback.
+ReadbackTestConfig const kTestConfigs[] = {
+ ReadbackTestConfig{LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP},
+ ReadbackTestConfig{LayerTreeTest::RENDERER_GL, READBACK_TEXTURE},
+ ReadbackTestConfig{LayerTreeTest::RENDERER_GL, READBACK_BITMAP},
+ ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE},
+ ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP},
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_VK, READBACK_BITMAP},
+#endif
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+ LayerTreeHostReadbackPixelTest,
+ ::testing::ValuesIn(kTestConfigs));
+
+// TODO(crbug.com/974283): These tests are crashing with vulkan when TSan or
+// MSan are used.
+ReadbackTestConfig const kMaybeVulkanTestConfigs[] = {
+ ReadbackTestConfig{LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP},
+ ReadbackTestConfig{LayerTreeTest::RENDERER_GL, READBACK_TEXTURE},
+ ReadbackTestConfig{LayerTreeTest::RENDERER_GL, READBACK_BITMAP},
+ ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE},
+ ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP},
+#if defined(ENABLE_CC_VULKAN_TESTS) && !defined(THREAD_SANITIZER) && \
+ !defined(MEMORY_SANITIZER)
+ ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_VK, READBACK_BITMAP},
+#endif
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+ LayerTreeHostReadbackPixelTestMaybeVulkan,
+ ::testing::ValuesIn(kMaybeVulkanTestConfigs));
class LayerTreeHostReadbackDeviceScalePixelTest
: public LayerTreeHostReadbackPixelTest {
@@ -434,11 +460,6 @@ class LayerTreeHostReadbackDeviceScalePixelTest
green_client_(SK_ColorGREEN, gfx::Size(200, 200)),
blue_client_(SK_ColorBLUE, gfx::Size(200, 200)) {}
- void InitializeSettings(LayerTreeSettings* settings) override {
- // Cause the device scale factor to be inherited by contents scales.
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-
void SetupTree() override {
SetInitialDeviceScaleFactor(device_scale_factor_);
LayerTreePixelTest::SetupTree();
@@ -510,15 +531,9 @@ TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackNonRootLayerSubrect) {
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-INSTANTIATE_TEST_SUITE_P(
- ,
- LayerTreeHostReadbackDeviceScalePixelTest,
- ::testing::Values(
- ReadbackTestConfig(LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP),
- ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_TEXTURE),
- ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_BITMAP),
- ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP),
- ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE)));
+INSTANTIATE_TEST_SUITE_P(,
+ LayerTreeHostReadbackDeviceScalePixelTest,
+ ::testing::ValuesIn(kTestConfigs));
class LayerTreeHostReadbackColorSpacePixelTest
: public LayerTreeHostReadbackPixelTest {
@@ -528,17 +543,17 @@ class LayerTreeHostReadbackColorSpacePixelTest
output_color_space_ = gfx::ColorSpace::CreateDisplayP3D65();
}
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
scoped_refptr<viz::RasterContextProvider> worker_context_provider)
override {
- std::unique_ptr<viz::TestLayerTreeFrameSink> frame_sink =
+ std::unique_ptr<TestLayerTreeFrameSink> frame_sink =
LayerTreePixelTest::CreateLayerTreeFrameSink(
renderer_settings, refresh_rate, compositor_context_provider,
worker_context_provider);
- frame_sink->SetDisplayColorSpace(output_color_space_, output_color_space_);
+ frame_sink->SetDisplayColorSpace(output_color_space_);
return frame_sink;
}
@@ -556,15 +571,9 @@ TEST_P(LayerTreeHostReadbackColorSpacePixelTest, Readback) {
base::FilePath(FILE_PATH_LITERAL("srgb_green_in_p3.png")));
}
-INSTANTIATE_TEST_SUITE_P(
- ,
- LayerTreeHostReadbackColorSpacePixelTest,
- ::testing::Values(
- ReadbackTestConfig(LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP),
- ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_TEXTURE),
- ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_BITMAP),
- ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP),
- ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE)));
+INSTANTIATE_TEST_SUITE_P(,
+ LayerTreeHostReadbackColorSpacePixelTest,
+ ::testing::ValuesIn(kTestConfigs));
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
index 8955987ba23..b271f513c0c 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -13,8 +13,8 @@
#include "cc/paint/paint_flags.h"
#include "cc/test/layer_tree_pixel_test.h"
#include "cc/test/pixel_comparator.h"
-#include "cc/test/test_in_process_context_provider.h"
#include "cc/trees/layer_tree_impl.h"
+#include "components/viz/test/test_in_process_context_provider.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#if !defined(OS_ANDROID)
@@ -30,10 +30,6 @@ class LayerTreeHostScrollbarsPixelTest
RendererType renderer_type() { return GetParam(); }
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-
void SetupTree() override {
SetInitialDeviceScaleFactor(device_scale_factor_);
LayerTreePixelTest::SetupTree();
@@ -89,10 +85,17 @@ class PaintedScrollbar : public Scrollbar {
gfx::Rect rect_;
};
+LayerTreeTest::RendererType const kRendererTypes[] = {
+ LayerTreeTest::RENDERER_GL,
+ LayerTreeTest::RENDERER_SKIA_GL,
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ LayerTreeTest::RENDERER_SKIA_VK,
+#endif
+};
+
INSTANTIATE_TEST_SUITE_P(,
LayerTreeHostScrollbarsPixelTest,
- ::testing::Values(LayerTreeTest::RENDERER_GL,
- LayerTreeTest::RENDERER_SKIA_GL));
+ ::testing::ValuesIn(kRendererTypes));
TEST_P(LayerTreeHostScrollbarsPixelTest, NoScale) {
scoped_refptr<SolidColorLayer> background =
@@ -167,9 +170,9 @@ TEST_P(LayerTreeHostScrollbarsPixelTest, MAYBE_HugeTransformScale) {
layer->SetBounds(gfx::Size(10, 400));
background->AddChild(layer);
- scoped_refptr<TestInProcessContextProvider> context(
- new TestInProcessContextProvider(/*enable_oop_rasterization=*/false,
- /*support_locking=*/false));
+ auto context = base::MakeRefCounted<viz::TestInProcessContextProvider>(
+ /*enable_oop_rasterization=*/false,
+ /*support_locking=*/false);
gpu::ContextResult result = context->BindToCurrentThread();
DCHECK_EQ(result, gpu::ContextResult::kSuccess);
int max_texture_size = 0;
@@ -189,7 +192,8 @@ TEST_P(LayerTreeHostScrollbarsPixelTest, MAYBE_HugeTransformScale) {
scale_transform.Scale(scale, scale);
layer->SetTransform(scale_transform);
- if (renderer_type() == RENDERER_SKIA_GL)
+ if (renderer_type() == RENDERER_SKIA_GL ||
+ renderer_type() == RENDERER_SKIA_VK)
pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true);
RunPixelTest(renderer_type(), background,
@@ -256,8 +260,7 @@ class PaintedOverlayScrollbar : public PaintedScrollbar {
INSTANTIATE_TEST_SUITE_P(,
LayerTreeHostOverlayScrollbarsPixelTest,
- ::testing::Values(LayerTreeTest::RENDERER_GL,
- LayerTreeTest::RENDERER_SKIA_GL));
+ ::testing::ValuesIn(kRendererTypes));
// Simulate increasing the thickness of a painted overlay scrollbar. Ensure that
// the scrollbar border remains crisp.
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc
index fac28b34708..708eefad33a 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc
@@ -54,10 +54,17 @@ class LayerTreeHostSynchronousPixelTest
bool use_zero_copy_ = false;
};
+LayerTreeTest::RendererType const kRendererTypesGpu[] = {
+ LayerTreeTest::RENDERER_GL,
+ LayerTreeTest::RENDERER_SKIA_GL,
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ LayerTreeTest::RENDERER_SKIA_VK,
+#endif
+};
+
INSTANTIATE_TEST_SUITE_P(,
LayerTreeHostSynchronousPixelTest,
- ::testing::Values(LayerTreeTest::RENDERER_GL,
- LayerTreeTest::RENDERER_SKIA_GL));
+ ::testing::ValuesIn(kRendererTypesGpu));
TEST_P(LayerTreeHostSynchronousPixelTest, OneContentLayerZeroCopy) {
use_zero_copy_ = true;
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
index ad22f279d6a..0da4873f16f 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -11,8 +11,8 @@
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_op_buffer.h"
#include "cc/test/layer_tree_pixel_test.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
#include "gpu/command_buffer/client/raster_interface.h"
#if !defined(OS_ANDROID)
@@ -172,15 +172,21 @@ class LayerTreeHostTilesTestPartialInvalidation
scoped_refptr<PictureLayer> picture_layer_;
};
-INSTANTIATE_TEST_SUITE_P(
- ,
- LayerTreeHostTilesTestPartialInvalidation,
- ::testing::Values(TilesTestConfig{LayerTreeTest::RENDERER_SOFTWARE, BITMAP},
- TilesTestConfig{LayerTreeTest::RENDERER_GL, ONE_COPY},
- TilesTestConfig{LayerTreeTest::RENDERER_GL, GPU},
- TilesTestConfig{LayerTreeTest::RENDERER_SKIA_GL,
- ONE_COPY},
- TilesTestConfig{LayerTreeTest::RENDERER_SKIA_GL, GPU}));
+std::vector<TilesTestConfig> const kTestCases = {
+ {LayerTreeTest::RENDERER_SOFTWARE, BITMAP},
+ {LayerTreeTest::RENDERER_GL, ONE_COPY},
+ {LayerTreeTest::RENDERER_GL, GPU},
+ {LayerTreeTest::RENDERER_SKIA_GL, ONE_COPY},
+ {LayerTreeTest::RENDERER_SKIA_GL, GPU},
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ {LayerTreeTest::RENDERER_SKIA_VK, ONE_COPY},
+ {LayerTreeTest::RENDERER_SKIA_VK, GPU},
+#endif
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+ LayerTreeHostTilesTestPartialInvalidation,
+ ::testing::ValuesIn(kTestCases));
TEST_P(LayerTreeHostTilesTestPartialInvalidation, PartialRaster) {
use_partial_raster_ = true;
@@ -195,15 +201,20 @@ TEST_P(LayerTreeHostTilesTestPartialInvalidation, FullRaster) {
base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png")));
}
+std::vector<TilesTestConfig> const kTestCasesMultiThread = {
+ {LayerTreeTest::RENDERER_GL, ONE_COPY},
+ {LayerTreeTest::RENDERER_SKIA_GL, ONE_COPY},
+#if defined(ENABLE_CC_VULKAN_TESTS)
+ {LayerTreeTest::RENDERER_SKIA_VK, ONE_COPY},
+#endif
+};
+
using LayerTreeHostTilesTestPartialInvalidationMultiThread =
LayerTreeHostTilesTestPartialInvalidation;
-INSTANTIATE_TEST_SUITE_P(
- ,
- LayerTreeHostTilesTestPartialInvalidationMultiThread,
- ::testing::Values(TilesTestConfig{LayerTreeTest::RENDERER_GL, ONE_COPY},
- TilesTestConfig{LayerTreeTest::RENDERER_SKIA_GL,
- ONE_COPY}));
+INSTANTIATE_TEST_SUITE_P(,
+ LayerTreeHostTilesTestPartialInvalidationMultiThread,
+ ::testing::ValuesIn(kTestCasesMultiThread));
// Flaky on Linux TSAN. https://crbug.com/707711
#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
@@ -227,6 +238,7 @@ TEST_P(LayerTreeHostTilesTestPartialInvalidationMultiThread, FullRaster) {
using LayerTreeHostTilesTestPartialInvalidationLowBitDepth =
LayerTreeHostTilesTestPartialInvalidation;
+// TODO(crbug.com/963446): Enable these tests for Vulkan.
INSTANTIATE_TEST_SUITE_P(
,
LayerTreeHostTilesTestPartialInvalidationLowBitDepth,
diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc
index f10dada2a20..023517fc874 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -47,6 +47,7 @@
#include "cc/test/push_properties_counting_layer_impl.h"
#include "cc/test/render_pass_test_utils.h"
#include "cc/test/skia_common.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "cc/trees/clip_node.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/frame_rate_counter.h"
@@ -69,7 +70,6 @@
#include "components/viz/test/begin_frame_args_test.h"
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/test_gles2_interface.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/khronos/GLES2/gl2.h"
@@ -501,7 +501,7 @@ SINGLE_THREAD_TEST_F(LayerTreeHostTestReadyToDrawVisibility);
class LayerTreeHostContextCacheTest : public LayerTreeHostTest {
public:
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -2468,10 +2468,6 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterDeviceSizeChanged);
class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest {
public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-
void SetupTree() override {
root_layer_ = Layer::Create();
root_layer_->SetBounds(gfx::Size(10, 20));
@@ -2519,10 +2515,6 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoExtraCommitFromInvalidate);
class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate
: public LayerTreeHostTest {
public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-
void SetupTree() override {
root_layer_ = Layer::Create();
root_layer_->SetBounds(gfx::Size(10, 20));
@@ -2578,10 +2570,6 @@ SINGLE_AND_MULTI_THREAD_TEST_F(
class LayerTreeHostTestDeviceScaleFactorChange : public LayerTreeHostTest {
public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-
void SetupTree() override {
root_layer_ = Layer::Create();
root_layer_->SetBounds(gfx::Size(10, 20));
@@ -4006,25 +3994,25 @@ class LayerTreeHostTestLCDChange : public LayerTreeHostTest {
// The first draw.
EXPECT_EQ(1, num_tiles_rastered_);
EXPECT_TRUE(can_use_lcd_text);
- EXPECT_TRUE(root_layer->RasterSourceUsesLCDTextForTesting());
+ EXPECT_TRUE(root_layer->can_use_lcd_text());
break;
case 1:
// Nothing changed on the layer.
EXPECT_EQ(1, num_tiles_rastered_);
EXPECT_TRUE(can_use_lcd_text);
- EXPECT_TRUE(root_layer->RasterSourceUsesLCDTextForTesting());
+ EXPECT_TRUE(root_layer->can_use_lcd_text());
break;
case 2:
// LCD text was disabled; it should be re-rastered with LCD text off.
EXPECT_EQ(2, num_tiles_rastered_);
EXPECT_FALSE(can_use_lcd_text);
- EXPECT_FALSE(root_layer->RasterSourceUsesLCDTextForTesting());
+ EXPECT_FALSE(root_layer->can_use_lcd_text());
break;
case 3:
// LCD text was enabled, but it's sticky and stays off.
EXPECT_EQ(2, num_tiles_rastered_);
EXPECT_TRUE(can_use_lcd_text);
- EXPECT_FALSE(root_layer->RasterSourceUsesLCDTextForTesting());
+ EXPECT_FALSE(root_layer->can_use_lcd_text());
break;
}
}
@@ -4106,7 +4094,7 @@ class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
int commit_complete_count_;
};
-class OnDrawLayerTreeFrameSink : public viz::TestLayerTreeFrameSink {
+class OnDrawLayerTreeFrameSink : public TestLayerTreeFrameSink {
public:
OnDrawLayerTreeFrameSink(
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -4148,7 +4136,7 @@ class LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor
settings->using_synchronous_renderer_compositor = true;
}
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -4406,37 +4394,36 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest {
// The scrollbar layer always needs to be pushed.
if (root_->layer_tree_host()) {
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
root_->layer_tree_host()->LayersThatShouldPushProperties(),
root_.get()));
}
if (child2_->layer_tree_host()) {
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
child2_->layer_tree_host()->LayersThatShouldPushProperties(),
child2_.get()));
}
if (leaf_always_pushing_layer_->layer_tree_host()) {
leaf_always_pushing_layer_->SetNeedsPushProperties();
- EXPECT_TRUE(
- base::ContainsKey(leaf_always_pushing_layer_->layer_tree_host()
- ->LayersThatShouldPushProperties(),
- leaf_always_pushing_layer_.get()));
+ EXPECT_TRUE(base::Contains(leaf_always_pushing_layer_->layer_tree_host()
+ ->LayersThatShouldPushProperties(),
+ leaf_always_pushing_layer_.get()));
}
// child_ and grandchild_ don't persist their need to push properties.
if (child_->layer_tree_host()) {
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
child_->layer_tree_host()->LayersThatShouldPushProperties(),
child_.get()));
}
if (grandchild_->layer_tree_host()) {
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
grandchild_->layer_tree_host()->LayersThatShouldPushProperties(),
grandchild_.get()));
}
if (other_root_->layer_tree_host()) {
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
other_root_->layer_tree_host()->LayersThatShouldPushProperties(),
other_root_.get()));
}
@@ -4789,9 +4776,9 @@ class LayerTreeHostTestPropertyChangesDuringUpdateArePushed
scrollbar_layer_->SetBounds(gfx::Size(30, 30));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- scrollbar_layer_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ scrollbar_layer_.get()));
layer_tree_host()->SetNeedsCommit();
scrollbar_layer_->reset_push_properties_count();
@@ -4835,9 +4822,9 @@ class LayerTreeHostTestSetDrawableCausesCommit : public LayerTreeHostTest {
// avoid causing a second commit to be scheduled. If a property change
// is made during this, however, it needs to be pushed in the upcoming
// commit.
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
EXPECT_EQ(0, root_->NumDescendantsThatDrawContent());
root_->reset_push_properties_count();
@@ -4846,18 +4833,18 @@ class LayerTreeHostTestSetDrawableCausesCommit : public LayerTreeHostTest {
EXPECT_EQ(1, root_->NumDescendantsThatDrawContent());
EXPECT_EQ(0u, root_->push_properties_count());
EXPECT_EQ(0u, child_->push_properties_count());
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
break;
}
case 2:
EXPECT_EQ(1u, root_->push_properties_count());
EXPECT_EQ(1u, child_->push_properties_count());
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
EndTest();
break;
@@ -4925,19 +4912,19 @@ class LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush
case 0:
// All layers will need push properties as we set their layer tree host
layer_tree_host()->SetRootLayer(root_);
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
break;
case 1:
EndTest();
@@ -4958,81 +4945,81 @@ class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion
layer_tree_host()->SetRootLayer(root_);
break;
case 1:
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
grandchild1_->RemoveFromParent();
grandchild1_->SetPosition(gfx::PointF(1.f, 1.f));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
child_->AddChild(grandchild1_);
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
grandchild2_->SetPosition(gfx::PointF(1.f, 1.f));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
// grandchild2_ will still need a push properties.
grandchild1_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
// grandchild3_ does not need a push properties, so recursing should
// no longer be needed.
grandchild2_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
EndTest();
break;
@@ -5057,35 +5044,35 @@ class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence
layer_tree_host()->SetRootLayer(root_);
break;
case 1:
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
// grandchild2_ will still need a push properties.
grandchild1_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
// grandchild3_ does not need a push properties, so recursing should
// no longer be needed.
grandchild2_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
EndTest();
break;
@@ -5106,19 +5093,19 @@ class LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree
layer_tree_host()->SetRootLayer(root_);
break;
case 1:
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
// Change grandchildren while their parent is not in the tree.
child_->RemoveFromParent();
@@ -5126,39 +5113,39 @@ class LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree
grandchild2_->SetPosition(gfx::PointF(1.f, 1.f));
root_->AddChild(child_);
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
grandchild1_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
grandchild2_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
grandchild3_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
EndTest();
@@ -5180,55 +5167,55 @@ class LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild
layer_tree_host()->SetRootLayer(root_);
break;
case 1:
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
child_->SetPosition(gfx::PointF(1.f, 1.f));
grandchild1_->SetPosition(gfx::PointF(1.f, 1.f));
grandchild2_->SetPosition(gfx::PointF(1.f, 1.f));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
grandchild1_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
grandchild2_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
child_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
EndTest();
@@ -5250,55 +5237,55 @@ class LayerTreeHostTestPushPropertiesSetPropertyInChildThenParent
layer_tree_host()->SetRootLayer(root_);
break;
case 1:
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
grandchild1_->SetPosition(gfx::PointF(1.f, 1.f));
grandchild2_->SetPosition(gfx::PointF(1.f, 1.f));
child_->SetPosition(gfx::PointF(1.f, 1.f));
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild1_.get()));
- EXPECT_TRUE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild2_.get()));
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- grandchild3_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild1_.get()));
+ EXPECT_TRUE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild2_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ grandchild3_.get()));
grandchild1_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
grandchild2_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), child_.get()));
child_->RemoveFromParent();
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
layer_tree_host()->LayersThatShouldPushProperties(), root_.get()));
EndTest();
@@ -5460,9 +5447,9 @@ class LayerTreeHostTestPushHiddenLayer : public LayerTreeHostTest {
switch (layer_tree_host()->SourceFrameNumber()) {
case 1:
// The layer type used does not need to push properties every frame.
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- child_layer_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ child_layer_.get()));
// Change the bounds of the child layer, but make it skipped
// by CalculateDrawProperties.
@@ -5471,9 +5458,9 @@ class LayerTreeHostTestPushHiddenLayer : public LayerTreeHostTest {
break;
case 2:
// The bounds of the child layer were pushed to the impl side.
- EXPECT_FALSE(base::ContainsKey(
- layer_tree_host()->LayersThatShouldPushProperties(),
- child_layer_.get()));
+ EXPECT_FALSE(
+ base::Contains(layer_tree_host()->LayersThatShouldPushProperties(),
+ child_layer_.get()));
EndTest();
break;
@@ -6410,7 +6397,7 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestEmptyLayerGpuRasterization);
class LayerTreeHostWithGpuRasterizationTest : public LayerTreeHostTest {
protected:
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> ignored_compositor_context_provider,
@@ -6939,7 +6926,7 @@ class LayerTreeHostTestSynchronousCompositeSwapPromise
settings->use_zero_copy = true;
}
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -6949,7 +6936,7 @@ class LayerTreeHostTestSynchronousCompositeSwapPromise
bool synchronous_composite =
!HasImplThread() &&
!layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
- return std::make_unique<viz::TestLayerTreeFrameSink>(
+ return std::make_unique<TestLayerTreeFrameSink>(
compositor_context_provider, std::move(worker_context_provider),
gpu_memory_buffer_manager(), renderer_settings, ImplThreadTaskRunner(),
synchronous_composite, disable_display_vsync, refresh_rate);
@@ -7807,7 +7794,7 @@ class LayerTreeTestPageScaleFlags : public LayerTreeTest {
layer->IsAffectedByPageScale()
? this->affected_by_page_scale_
: this->not_affected_by_page_scale_;
- EXPECT_TRUE(base::ContainsValue(list, layer->id()));
+ EXPECT_TRUE(base::Contains(list, layer->id()));
});
EndTest();
@@ -8179,7 +8166,7 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSubmitFrameMetadata);
class LayerTreeHostTestSubmitFrameResources : public LayerTreeHostTest {
protected:
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -8248,33 +8235,6 @@ class LayerTreeHostTestSubmitFrameResources : public LayerTreeHostTest {
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSubmitFrameResources);
-// Ensure that content_source_id is propagated to the frame's metadata.
-class LayerTreeHostTestContentSourceId : public LayerTreeHostTest {
- protected:
- void BeginTest() override {
- layer_tree_host()->SetContentSourceId(5);
- PostSetNeedsCommitToMainThread();
- }
-
- DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- DrawResult draw_result) override {
- EXPECT_EQ(DRAW_SUCCESS, draw_result);
- EXPECT_EQ(5U, host_impl->active_tree()->content_source_id());
- return draw_result;
- }
-
- void DisplayReceivedCompositorFrameOnThread(
- const viz::CompositorFrame& frame) override {
- EXPECT_EQ(5U, frame.metadata.content_source_id);
- EndTest();
- }
-
- void AfterTest() override {}
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestContentSourceId);
-
class LayerTreeHostTestBeginFrameAcks : public LayerTreeHostTest {
protected:
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation.cc b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
index 47a27fd67c8..d5a0aa983c0 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
@@ -369,6 +369,15 @@ class LayerTreeHostAnimationTestAddKeyframeModelWithTimingFunction
if (host_impl->active_tree()->source_frame_number() != 0)
return;
+ // The impl thread may start a second frame before the test finishes. This
+ // can lead to a race as if the main thread has committed a new sync tree
+ // the impl thread can now delete the KeyframeModel as the animation only
+ // lasts a single frame and no longer affects either tree. Only test the
+ // first frame the animation shows up for.
+ if (!first_animation_frame_)
+ return;
+ first_animation_frame_ = false;
+
scoped_refptr<AnimationTimeline> timeline_impl =
GetImplAnimationHost(host_impl)->GetTimelineById(timeline_id_);
scoped_refptr<SingleKeyframeEffectAnimation> animation_child_impl =
@@ -397,6 +406,7 @@ class LayerTreeHostAnimationTestAddKeyframeModelWithTimingFunction
FakeContentLayerClient client_;
scoped_refptr<FakePictureLayer> picture_;
+ bool first_animation_frame_ = true;
};
SINGLE_AND_MULTI_THREAD_TEST_F(
@@ -712,13 +722,6 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations
animation_child_->set_animation_delegate(this);
}
- void InitializeSettings(LayerTreeSettings* settings) override {
- // Make sure that drawing many times doesn't cause a checkerboarded
- // animation to start so we avoid flake in this test.
- settings->timeout_and_draw_when_animation_checkerboards = false;
- LayerTreeHostAnimationTest::InitializeSettings(settings);
- }
-
void BeginTest() override {
prevented_draw_ = 0;
started_times_ = 0;
diff --git a/chromium/cc/trees/layer_tree_host_unittest_capture_content.cc b/chromium/cc/trees/layer_tree_host_unittest_capture_content.cc
index 75f69a3cbef..1b6d70d9527 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_capture_content.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_capture_content.cc
@@ -12,44 +12,42 @@
namespace cc {
namespace {
-class FakeTextHolder : public TextHolder {
+class FakeTextHolder {
public:
- FakeTextHolder(const std::string& text, const gfx::Rect& rect)
- : text_(text), rect_(rect) {}
+ FakeTextHolder(const std::string& text, const gfx::Rect& rect, NodeId node_id)
+ : text_(text), rect_(rect), node_id_(node_id) {}
std::string text() const { return text_; }
gfx::Rect rect() const { return rect_; }
-
- protected:
- ~FakeTextHolder() override = default;
+ NodeId node_id() const { return node_id_; }
private:
std::string text_;
gfx::Rect rect_;
+ NodeId node_id_;
};
class FakeCaptureContentLayerClient : public FakeContentLayerClient {
public:
- void addTextHolder(scoped_refptr<FakeTextHolder> holder) {
+ void addTextHolder(const FakeTextHolder& holder) {
holders_.push_back(holder);
}
scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
PaintingControlSetting painting_control) override {
auto display_list = base::MakeRefCounted<DisplayItemList>();
- for (auto holder : holders_) {
+ for (auto& holder : holders_) {
display_list->StartPaint();
display_list->push<DrawTextBlobOp>(
- SkTextBlob::MakeFromString(holder->text().data(), SkFont()),
- holder->rect().x(), holder->rect().y(), PaintFlags(),
- NodeHolder(holder));
- display_list->EndPaintOfUnpaired(holder->rect());
+ SkTextBlob::MakeFromString(holder.text().data(), SkFont()),
+ holder.rect().x(), holder.rect().y(), holder.node_id(), PaintFlags());
+ display_list->EndPaintOfUnpaired(holder.rect());
}
display_list->Finalize();
return display_list;
}
private:
- std::vector<scoped_refptr<FakeTextHolder>> holders_;
+ std::vector<const FakeTextHolder> holders_;
};
// These tests are for LayerTreeHost::CaptureContent().
@@ -58,8 +56,7 @@ class LayerTreeHostCaptureContentTest : public LayerTreeTest {
~LayerTreeHostCaptureContentTest() override = default;
protected:
- LayerTreeHostCaptureContentTest()
- : device_bounds_(10, 10), weak_factory_(this) {}
+ LayerTreeHostCaptureContentTest() : device_bounds_(10, 10) {}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
@@ -78,17 +75,13 @@ class LayerTreeHostCaptureContentTest : public LayerTreeTest {
layer_tree_host()->SetViewportVisibleRect(gfx::Rect(device_bounds_));
}
- void VerifyCapturedContent(
- std::vector<scoped_refptr<FakeTextHolder>>* expected_result) {
+ void VerifyCapturedContent(std::vector<FakeTextHolder>* expected_result) {
EXPECT_EQ(expected_result->size(), captured_content_.size());
size_t expected_left_result = expected_result->size();
- for (auto c : captured_content_) {
- EXPECT_EQ(c.type, NodeHolder::Type::kTextHolder);
+ for (auto& c : captured_content_) {
for (auto it = expected_result->begin(); it != expected_result->end();
++it) {
- if (it->get() == c.text_holder.get()) {
- EXPECT_EQ(static_cast<FakeTextHolder*>(c.text_holder.get())->text(),
- it->get()->text());
+ if (it->node_id() == c) {
expected_result->erase(it);
break;
}
@@ -114,23 +107,23 @@ class LayerTreeHostCaptureContentTest : public LayerTreeTest {
}
scoped_refptr<FakePictureLayer> root_picture_layer_;
- std::vector<NodeHolder> captured_content_;
+ std::vector<NodeId> captured_content_;
const gfx::Size device_bounds_;
- base::WeakPtrFactory<LayerTreeHostCaptureContentTest> weak_factory_;
+ base::WeakPtrFactory<LayerTreeHostCaptureContentTest> weak_factory_{this};
};
class LayerTreeHostCaptureContentTestBasic
: public LayerTreeHostCaptureContentTest {
protected:
void SetupTextHolders(const gfx::Rect& rect1, const gfx::Rect& rect2) {
- text_holder_1_ = base::MakeRefCounted<FakeTextHolder>("Text1", rect1);
- client_.addTextHolder(text_holder_1_);
- text_holder_2_ = base::MakeRefCounted<FakeTextHolder>("Text2", rect2);
- client_.addTextHolder(text_holder_2_);
+ text_holder_1_ = std::make_unique<FakeTextHolder>("Text1", rect1, 1);
+ client_.addTextHolder(*text_holder_1_);
+ text_holder_2_ = std::make_unique<FakeTextHolder>("Text2", rect2, 2);
+ client_.addTextHolder(*text_holder_2_);
}
- scoped_refptr<FakeTextHolder> text_holder_1_;
- scoped_refptr<FakeTextHolder> text_holder_2_;
+ std::unique_ptr<FakeTextHolder> text_holder_1_;
+ std::unique_ptr<FakeTextHolder> text_holder_2_;
};
// Test that one DrawTextBlobOp is on-screen, another isn't.
@@ -144,8 +137,8 @@ class LayerTreeHostCaptureContentTestOneVisible
}
void AfterTest() override {
- std::vector<scoped_refptr<FakeTextHolder>> expected_result;
- expected_result.push_back(text_holder_1_);
+ std::vector<FakeTextHolder> expected_result;
+ expected_result.push_back(*text_holder_1_);
VerifyCapturedContent(&expected_result);
}
};
@@ -163,9 +156,9 @@ class LayerTreeHostCaptureContentTestTwoVisible
}
void AfterTest() override {
- std::vector<scoped_refptr<FakeTextHolder>> expected_result;
- expected_result.push_back(text_holder_1_);
- expected_result.push_back(text_holder_2_);
+ std::vector<FakeTextHolder> expected_result;
+ expected_result.push_back(*text_holder_1_);
+ expected_result.push_back(*text_holder_2_);
VerifyCapturedContent(&expected_result);
}
};
@@ -208,11 +201,11 @@ class LayerTreeHostCaptureContentTestTwoLayers
void SetupSecondaryPictureLayer(const gfx::Size& size) {
// Add text to layer.
text_holder_21_ =
- base::MakeRefCounted<FakeTextHolder>("Text21", gfx::Rect(0, 0, 10, 5));
- client2_.addTextHolder(text_holder_21_);
+ std::make_unique<FakeTextHolder>("Text21", gfx::Rect(0, 0, 10, 5), 21);
+ client2_.addTextHolder(*text_holder_21_);
text_holder_22_ =
- base::MakeRefCounted<FakeTextHolder>("Text22", gfx::Rect(0, 5, 10, 5));
- client2_.addTextHolder(text_holder_22_);
+ std::make_unique<FakeTextHolder>("Text22", gfx::Rect(0, 5, 10, 5), 22);
+ client2_.addTextHolder(*text_holder_22_);
client2_.set_bounds(size);
// Create layer.
@@ -223,8 +216,8 @@ class LayerTreeHostCaptureContentTestTwoLayers
}
scoped_refptr<FakePictureLayer> picture_layer;
- scoped_refptr<FakeTextHolder> text_holder_21_;
- scoped_refptr<FakeTextHolder> text_holder_22_;
+ std::unique_ptr<FakeTextHolder> text_holder_21_;
+ std::unique_ptr<FakeTextHolder> text_holder_22_;
FakeCaptureContentLayerClient client2_;
};
@@ -237,9 +230,9 @@ class LayerTreeHostCaptureContentTestOneLayerVisible
}
void AfterTest() override {
- std::vector<scoped_refptr<FakeTextHolder>> expected_result;
- expected_result.push_back(text_holder_1_);
- expected_result.push_back(text_holder_2_);
+ std::vector<FakeTextHolder> expected_result;
+ expected_result.push_back(*text_holder_1_);
+ expected_result.push_back(*text_holder_2_);
VerifyCapturedContent(&expected_result);
}
};
@@ -256,10 +249,10 @@ class LayerTreeHostCaptureContentTestTwoLayersVisible
}
void AfterTest() override {
- std::vector<scoped_refptr<FakeTextHolder>> expected_result;
- expected_result.push_back(text_holder_1_);
- expected_result.push_back(text_holder_2_);
- expected_result.push_back(text_holder_21_);
+ std::vector<FakeTextHolder> expected_result;
+ expected_result.push_back(*text_holder_1_);
+ expected_result.push_back(*text_holder_2_);
+ expected_result.push_back(*text_holder_21_);
VerifyCapturedContent(&expected_result);
}
};
@@ -274,10 +267,10 @@ class LayerTreeHostCaptureContentTestTwoLayersVisibleAndTransparent
void AfterTest() override {
// All 3 TextHolders are returned.
- std::vector<scoped_refptr<FakeTextHolder>> expected_result;
- expected_result.push_back(text_holder_1_);
- expected_result.push_back(text_holder_2_);
- expected_result.push_back(text_holder_21_);
+ std::vector<FakeTextHolder> expected_result;
+ expected_result.push_back(*text_holder_1_);
+ expected_result.push_back(*text_holder_2_);
+ expected_result.push_back(*text_holder_21_);
VerifyCapturedContent(&expected_result);
}
};
@@ -295,11 +288,11 @@ class LayerTreeHostCaptureContentTestUpperLayerPartialOverlay
}
void AfterTest() override {
- std::vector<scoped_refptr<FakeTextHolder>> expected_result;
- expected_result.push_back(text_holder_1_);
- expected_result.push_back(text_holder_2_);
- expected_result.push_back(text_holder_21_);
- expected_result.push_back(text_holder_22_);
+ std::vector<FakeTextHolder> expected_result;
+ expected_result.push_back(*text_holder_1_);
+ expected_result.push_back(*text_holder_2_);
+ expected_result.push_back(*text_holder_21_);
+ expected_result.push_back(*text_holder_22_);
VerifyCapturedContent(&expected_result);
}
};
diff --git a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
index 5ad5e2a6977..dfdecdb3ef6 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
@@ -7,11 +7,11 @@
#include "cc/test/fake_picture_layer.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/skia_common.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_impl.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/viz/test/begin_frame_args_test.h"
#include "components/viz/test/fake_external_begin_frame_source.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
namespace cc {
namespace {
diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc
index a06f23dc57f..b658d15f6fe 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_context.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc
@@ -29,6 +29,7 @@
#include "cc/test/fake_video_frame_provider.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/render_pass_test_utils.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
@@ -38,7 +39,6 @@
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gles2_interface.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
#include "components/viz/test/test_shared_bitmap_manager.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/raster_interface.h"
@@ -85,7 +85,7 @@ class LayerTreeHostContextTest : public LayerTreeTest {
gl_ = nullptr;
}
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -1682,7 +1682,7 @@ SINGLE_AND_MULTI_THREAD_TEST_F(TileResourceFreedIfLostWhileExported);
class SoftwareTileResourceFreedIfLostWhileExported : public LayerTreeTest {
protected:
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 5bac6e88f25..3f335e7d9d5 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -13,6 +13,7 @@
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/layer_tree_test.h"
+#include "cc/test/test_layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_impl.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
@@ -20,7 +21,6 @@
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/fake_skia_output_surface.h"
#include "components/viz/test/test_gles2_interface.h"
-#include "components/viz/test/test_layer_tree_frame_sink.h"
#include "gpu/GLES2/gl2extchromium.h"
namespace cc {
@@ -514,7 +514,7 @@ class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest
client_.set_bounds(root_->bounds());
}
- std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
@@ -589,7 +589,7 @@ class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest
viz::RenderPassId parent_render_pass_id = 0;
viz::RenderPassId copy_layer_render_pass_id = 0;
- viz::TestLayerTreeFrameSink* frame_sink_ = nullptr;
+ TestLayerTreeFrameSink* frame_sink_ = nullptr;
bool did_swap_ = false;
FakeContentLayerClient client_;
scoped_refptr<FakePictureLayer> root_;
@@ -671,10 +671,6 @@ TEST_P(LayerTreeHostCopyRequestTestClippedOut, Test) {
class LayerTreeHostCopyRequestTestScaledLayer
: public LayerTreeHostCopyRequestTest {
protected:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-
void SetupTree() override {
root_ = Layer::Create();
root_->SetBounds(gfx::Size(20, 20));
diff --git a/chromium/cc/trees/layer_tree_host_unittest_masks.cc b/chromium/cc/trees/layer_tree_host_unittest_masks.cc
index b0a8b0c9ac2..3870aba8671 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_masks.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_masks.cc
@@ -50,7 +50,7 @@ class LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin
gfx::Size mask_size(100, 100);
mask_layer->SetBounds(mask_size);
- mask_layer->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask_layer->SetLayerMaskType(Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
mask_layer_id_ = mask_layer->id();
layer_tree_host()->SetRootLayer(root);
@@ -89,21 +89,9 @@ class LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin
render_pass_quad->rect);
EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
rect_in_target_space.ToString());
- if (host_impl->settings().enable_mask_tiling) {
- PictureLayerImpl* mask_layer_impl = static_cast<PictureLayerImpl*>(
- host_impl->active_tree()->LayerById(mask_layer_id_));
- gfx::SizeF texture_size(
- mask_layer_impl->CalculateTileSize(mask_layer_impl->bounds()));
- EXPECT_EQ(
- gfx::RectF(50.f / texture_size.width(), 50.f / texture_size.height(),
- 50.f / texture_size.width(), 50.f / texture_size.height())
- .ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- } else {
- EXPECT_EQ(gfx::ScaleRect(gfx::RectF(50.f, 50.f, 50.f, 50.f), 1.f / 100.f)
- .ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- }
+ EXPECT_EQ(gfx::ScaleRect(gfx::RectF(50.f, 50.f, 50.f, 50.f), 1.f / 100.f)
+ .ToString(),
+ render_pass_quad->mask_uv_rect.ToString());
EndTest();
return draw_result;
}
@@ -114,27 +102,8 @@ class LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin
FakeContentLayerClient client_;
};
-class LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin_Untiled
- : public LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = false;
- }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin_Untiled);
-
-class LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin_Tiled
- : public LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = true;
- }
-};
-
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin_Tiled);
+ LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin);
class LayerTreeTestMaskLayerForSurfaceWithClippedLayer : public LayerTreeTest {
protected:
@@ -191,7 +160,7 @@ class LayerTreeTestMaskLayerForSurfaceWithClippedLayer : public LayerTreeTest {
gfx::Size mask_size(50, 50);
mask_layer->SetBounds(mask_size);
- mask_layer->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask_layer->SetLayerMaskType(Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
mask_layer_id_ = mask_layer->id();
layer_tree_host()->SetRootLayer(root);
@@ -226,21 +195,9 @@ class LayerTreeTestMaskLayerForSurfaceWithClippedLayer : public LayerTreeTest {
// coords in the mask are scaled by 10/50 and 20/50.
// The surface is clipped to (20,10) so the mask texture coords are offset
// by 20/50 and 10/50
- if (host_impl->settings().enable_mask_tiling) {
- PictureLayerImpl* mask_layer_impl = static_cast<PictureLayerImpl*>(
- host_impl->active_tree()->LayerById(mask_layer_id_));
- gfx::SizeF texture_size(
- mask_layer_impl->CalculateTileSize(mask_layer_impl->bounds()));
- EXPECT_EQ(
- gfx::RectF(20.f / texture_size.width(), 10.f / texture_size.height(),
- 10.f / texture_size.width(), 20.f / texture_size.height())
- .ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- } else {
- EXPECT_EQ(gfx::ScaleRect(gfx::RectF(20.f, 10.f, 10.f, 20.f), 1.f / 50.f)
- .ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- }
+ EXPECT_EQ(gfx::ScaleRect(gfx::RectF(20.f, 10.f, 10.f, 20.f), 1.f / 50.f)
+ .ToString(),
+ render_pass_quad->mask_uv_rect.ToString());
EndTest();
return draw_result;
}
@@ -251,27 +208,8 @@ class LayerTreeTestMaskLayerForSurfaceWithClippedLayer : public LayerTreeTest {
FakeContentLayerClient client_;
};
-class LayerTreeTestMaskLayerForSurfaceWithClippedLayer_Untiled
- : public LayerTreeTestMaskLayerForSurfaceWithClippedLayer {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = false;
- }
-};
-
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeTestMaskLayerForSurfaceWithClippedLayer_Untiled);
-
-class LayerTreeTestMaskLayerForSurfaceWithClippedLayer_Tiled
- : public LayerTreeTestMaskLayerForSurfaceWithClippedLayer {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = true;
- }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeTestMaskLayerForSurfaceWithClippedLayer_Tiled);
+ LayerTreeTestMaskLayerForSurfaceWithClippedLayer);
class LayerTreeTestMaskLayerForSurfaceWithDifferentScale
: public LayerTreeTest {
@@ -333,7 +271,7 @@ class LayerTreeTestMaskLayerForSurfaceWithDifferentScale
gfx::Size mask_size(50, 50);
mask_layer->SetBounds(mask_size);
- mask_layer->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask_layer->SetLayerMaskType(Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
// Setting will change transform on mask layer will make it not adjust
// raster scale, which will remain 1. This means the mask_layer and render
// surface will have a scale of 2 during draw time.
@@ -378,21 +316,9 @@ class LayerTreeTestMaskLayerForSurfaceWithDifferentScale
// coords in the mask are scaled by 10/50 and 20/50.
// The surface is clipped to (20,10) so the mask texture coords are offset
// by 20/50 and 10/50
- if (host_impl->settings().enable_mask_tiling) {
- PictureLayerImpl* mask_layer_impl = static_cast<PictureLayerImpl*>(
- host_impl->active_tree()->LayerById(mask_layer_id_));
- gfx::SizeF texture_size(
- mask_layer_impl->CalculateTileSize(mask_layer_impl->bounds()));
- EXPECT_EQ(
- gfx::RectF(20.f / texture_size.width(), 10.f / texture_size.height(),
- 10.f / texture_size.width(), 20.f / texture_size.height())
- .ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- } else {
- EXPECT_EQ(gfx::ScaleRect(gfx::RectF(20.f, 10.f, 10.f, 20.f), 1.f / 50.f)
- .ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- }
+ EXPECT_EQ(gfx::ScaleRect(gfx::RectF(20.f, 10.f, 10.f, 20.f), 1.f / 50.f)
+ .ToString(),
+ render_pass_quad->mask_uv_rect.ToString());
EndTest();
return draw_result;
}
@@ -403,27 +329,8 @@ class LayerTreeTestMaskLayerForSurfaceWithDifferentScale
FakeContentLayerClient client_;
};
-class LayerTreeTestMaskLayerForSurfaceWithDifferentScale_Untiled
- : public LayerTreeTestMaskLayerForSurfaceWithDifferentScale {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = false;
- }
-};
-
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeTestMaskLayerForSurfaceWithDifferentScale_Untiled);
-
-class LayerTreeTestMaskLayerForSurfaceWithDifferentScale_Tiled
- : public LayerTreeTestMaskLayerForSurfaceWithDifferentScale {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = true;
- }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeTestMaskLayerForSurfaceWithDifferentScale_Tiled);
+ LayerTreeTestMaskLayerForSurfaceWithDifferentScale);
class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest {
protected:
@@ -471,7 +378,7 @@ class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest {
content_layer->SetBounds(scaling_layer_size);
mask_layer->SetBounds(scaling_layer_size);
- mask_layer->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask_layer->SetLayerMaskType(Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
@@ -495,34 +402,25 @@ class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest {
root_pass->quad_list.front()->material);
const viz::RenderPassDrawQuad* render_pass_quad =
viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
+ gfx::Rect rect_in_target_space = MathUtil::MapEnclosingClippedRect(
+ render_pass_quad->shared_quad_state->quad_to_target_transform,
+ render_pass_quad->rect);
switch (host_impl->active_tree()->source_frame_number()) {
case 0:
// Check that the tree scaling is correctly taken into account for the
// mask, that should fully map onto the quad.
EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- render_pass_quad->rect.ToString());
- if (host_impl->settings().enable_mask_tiling) {
- EXPECT_EQ(
- gfx::RectF(0.f, 0.f, 100.f / 128.f, 100.f / 128.f).ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- } else {
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- }
+ rect_in_target_space.ToString());
+ EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
+ render_pass_quad->mask_uv_rect.ToString());
break;
case 1:
// Applying a DSF should change the render surface size, but won't
// affect which part of the mask is used.
EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
- render_pass_quad->rect.ToString());
- if (host_impl->settings().enable_mask_tiling) {
- EXPECT_EQ(
- gfx::RectF(0.f, 0.f, 100.f / 128.f, 100.f / 128.f).ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- } else {
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- render_pass_quad->mask_uv_rect.ToString());
- }
+ rect_in_target_space.ToString());
+ EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
+ render_pass_quad->mask_uv_rect.ToString());
EndTest();
break;
}
@@ -544,27 +442,7 @@ class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest {
FakeContentLayerClient client_;
};
-class LayerTreeTestMaskLayerWithScaling_Untiled
- : public LayerTreeTestMaskLayerWithScaling {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = false;
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskLayerWithScaling_Untiled);
-
-class LayerTreeTestMaskLayerWithScaling_Tiled
- : public LayerTreeTestMaskLayerWithScaling {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = true;
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskLayerWithScaling_Tiled);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskLayerWithScaling);
class LayerTreeTestMaskWithNonExactTextureSize : public LayerTreeTest {
protected:
@@ -642,26 +520,7 @@ class LayerTreeTestMaskWithNonExactTextureSize : public LayerTreeTest {
FakeContentLayerClient client_;
};
-class LayerTreeTestMaskWithNonExactTextureSize_Untiled
- : public LayerTreeTestMaskWithNonExactTextureSize {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = false;
- }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeTestMaskWithNonExactTextureSize_Untiled);
-
-class LayerTreeTestMaskWithNonExactTextureSize_Tiled
- : public LayerTreeTestMaskWithNonExactTextureSize {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_mask_tiling = true;
- }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskWithNonExactTextureSize_Tiled);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskWithNonExactTextureSize);
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_picture.cc b/chromium/cc/trees/layer_tree_host_unittest_picture.cc
index feea9ffa2cb..8c103dfc473 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_picture.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_picture.cc
@@ -439,10 +439,6 @@ class LayerTreeHostPictureTestRSLLMembershipWithScale
client_.set_bounds(picture_->bounds());
}
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-
void BeginTest() override {
frame_ = 0;
draws_in_frame_ = 0;
@@ -607,10 +603,6 @@ class LayerTreeHostPictureTestForceRecalculateScales
client_.set_bounds(size);
}
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
index 667f67d8909..8ebf210f056 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -25,6 +25,8 @@
#include "cc/test/layer_tree_test.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_ukm_recorder_factory.h"
+#include "cc/trees/clip_node.h"
+#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/scroll_node.h"
@@ -977,7 +979,7 @@ class LayerTreeHostScrollTestImplOnlyScroll : public LayerTreeHostScrollTest {
Layer* scroll_layer = layer_tree_host()->outer_viewport_scroll_layer();
switch (layer_tree_host()->SourceFrameNumber()) {
case 0:
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
scroll_layer->layer_tree_host()->LayersThatShouldPushProperties(),
scroll_layer));
break;
@@ -985,7 +987,7 @@ class LayerTreeHostScrollTestImplOnlyScroll : public LayerTreeHostScrollTest {
// Even if this layer doesn't need push properties, it should
// still pick up scrolls that happen on the active layer during
// commit.
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
scroll_layer->layer_tree_host()->LayersThatShouldPushProperties(),
scroll_layer));
break;
@@ -1155,8 +1157,7 @@ class LayerTreeHostScrollTestScrollZeroMaxScrollOffset
ScrollNode* scroll_node =
scroll_tree.Node(scroll_layer->scroll_tree_index());
InputHandler::ScrollStatus status =
- impl->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::TOUCHSCREEN,
- scroll_tree, scroll_node);
+ impl->TryScroll(gfx::PointF(0.0f, 1.0f), scroll_tree, scroll_node);
switch (impl->active_tree()->source_frame_number()) {
case 0:
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
@@ -1206,26 +1207,17 @@ class LayerTreeHostScrollTestScrollNonDrawnLayer
}
void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
- LayerImpl* scroll_layer = impl->OuterViewportScrollLayer();
-
- ScrollTree& scroll_tree =
- impl->active_tree()->property_trees()->scroll_tree;
- ScrollNode* scroll_node =
- scroll_tree.Node(scroll_layer->scroll_tree_index());
-
// Verify that the scroll layer's scroll offset is taken into account when
// checking whether the screen space point is inside the non-fast
// scrollable region.
-
- InputHandler::ScrollStatus status =
- impl->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::TOUCHSCREEN,
- scroll_tree, scroll_node);
+ InputHandler::ScrollStatus status = impl->ScrollBegin(
+ BeginState(gfx::Point(0, 0)).get(), InputHandler::TOUCHSCREEN);
EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
status.main_thread_scrolling_reasons);
- status = impl->TryScroll(gfx::PointF(21.f, 21.f), InputHandler::TOUCHSCREEN,
- scroll_tree, scroll_node);
+ status = impl->ScrollBegin(BeginState(gfx::Point(21, 21)).get(),
+ InputHandler::TOUCHSCREEN);
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
status.main_thread_scrolling_reasons);
@@ -1265,14 +1257,13 @@ class LayerTreeHostScrollTestImplScrollUnderMainThreadScrollingParent
scroll_tree.Node(outer_scroll_layer->scroll_tree_index());
InputHandler::ScrollStatus status =
- impl->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::TOUCHSCREEN,
- scroll_tree, inner_scroll_node);
+ impl->TryScroll(gfx::PointF(1.f, 1.f), scroll_tree, inner_scroll_node);
EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kScrollbarScrolling,
status.main_thread_scrolling_reasons);
- status = impl->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::TOUCHSCREEN,
- scroll_tree, outer_scroll_node);
+ status =
+ impl->TryScroll(gfx::PointF(1.f, 1.f), scroll_tree, outer_scroll_node);
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
status.main_thread_scrolling_reasons);
@@ -1321,12 +1312,18 @@ class ThreadCheckingInputHandlerClient : public InputHandlerClient {
}
}
- void DeliverInputForBeginFrame() override {
+ void DeliverInputForBeginFrame(const viz::BeginFrameArgs& args) override {
if (!task_runner_->BelongsToCurrentThread()) {
ADD_FAILURE() << "DeliverInputForBeginFrame called on wrong thread";
}
}
+ void DeliverInputForHighLatencyMode() override {
+ if (!task_runner_->BelongsToCurrentThread()) {
+ ADD_FAILURE() << "DeliverInputForHighLatencyMode called on wrong thread";
+ }
+ }
+
private:
base::SingleThreadTaskRunner* task_runner_;
bool* received_stop_flinging_;
@@ -1825,7 +1822,8 @@ class MockInputHandlerClient : public InputHandlerClient {
float page_scale_factor,
float min_page_scale_factor,
float max_page_scale_factor) override {}
- void DeliverInputForBeginFrame() override {}
+ void DeliverInputForBeginFrame(const viz::BeginFrameArgs& args) override {}
+ void DeliverInputForHighLatencyMode() override {}
};
// This is a regression test, see crbug.com/639046.
@@ -2233,5 +2231,189 @@ class LayerTreeHostScrollTestImplSideInvalidation
MULTI_THREAD_TEST_F(LayerTreeHostScrollTestImplSideInvalidation);
+// Version of LayerTreeHostScrollTest that uses layer lists which means the
+// property trees and layer list are explicitly specified instead of running
+// the cc property tree builder.
+class LayerListLayerTreeHostScrollTest : public LayerTreeHostScrollTest {
+ public:
+ // The id of the root property tree nodes.
+ static constexpr int kRootNodeId = 1;
+
+ LayerListLayerTreeHostScrollTest() { SetUseLayerList(); }
+
+ void SetupTree() override {
+ // Setup the root transform, effect, clip, and scroll property tree nodes.
+ auto& transform_tree = layer_tree_host()->property_trees()->transform_tree;
+ auto& root_transform_node = *transform_tree.Node(
+ transform_tree.Insert(TransformNode(), kRealRootNodeId));
+ DCHECK_EQ(root_transform_node.id, kRootNodeId);
+ root_transform_node.source_node_id = root_transform_node.parent_id;
+ transform_tree.set_needs_update(true);
+
+ auto& effect_tree = layer_tree_host()->property_trees()->effect_tree;
+ auto& root_effect_node =
+ *effect_tree.Node(effect_tree.Insert(EffectNode(), kRealRootNodeId));
+ DCHECK_EQ(root_effect_node.id, kRootNodeId);
+ root_effect_node.stable_id = 1;
+ root_effect_node.transform_id = kRealRootNodeId;
+ root_effect_node.clip_id = kRealRootNodeId;
+ root_effect_node.render_surface_reason = RenderSurfaceReason::kRoot;
+ effect_tree.set_needs_update(true);
+
+ auto& clip_tree = layer_tree_host()->property_trees()->clip_tree;
+ auto& root_clip_node =
+ *clip_tree.Node(clip_tree.Insert(ClipNode(), kRealRootNodeId));
+ DCHECK_EQ(root_clip_node.id, kRootNodeId);
+ root_clip_node.clip_type = ClipNode::ClipType::APPLIES_LOCAL_CLIP;
+ root_clip_node.clip = gfx::RectF(gfx::SizeF(800, 600));
+ root_clip_node.transform_id = kRealRootNodeId;
+ clip_tree.set_needs_update(true);
+
+ auto& scroll_tree = layer_tree_host()->property_trees()->scroll_tree;
+ auto& root_scroll_node =
+ *scroll_tree.Node(scroll_tree.Insert(ScrollNode(), kRealRootNodeId));
+ DCHECK_EQ(root_scroll_node.id, kRootNodeId);
+ root_scroll_node.transform_id = kRealRootNodeId;
+ scroll_tree.set_needs_update(true);
+
+ // Setup the root Layer which should be used to attach the layer list.
+ root_ = Layer::Create();
+ root_->SetBounds(gfx::Size(800, 600));
+ root_->SetIsDrawable(true);
+ root_->SetHitTestable(true);
+ root_->SetTransformTreeIndex(root_transform_node.id);
+ root_->SetEffectTreeIndex(root_effect_node.id);
+ root_->SetScrollTreeIndex(root_scroll_node.id);
+ root_->SetClipTreeIndex(root_clip_node.id);
+ layer_tree_host()->SetRootLayer(root_);
+
+ layer_tree_host()->SetViewportSizeAndScale(gfx::Size(800, 600), 1.f,
+ viz::LocalSurfaceIdAllocation());
+
+ layer_tree_host()->property_trees()->sequence_number =
+ root_->property_tree_sequence_number();
+
+ root_->SetNeedsCommit();
+ }
+
+ Layer* root() const { return root_.get(); }
+
+ private:
+ // The compositor is hard-coded to use 0 for the root nodes (always non-null).
+ static constexpr int kRealRootNodeId = 0;
+
+ scoped_refptr<Layer> root_;
+};
+
+class NonScrollingNonFastScrollableRegion
+ : public LayerListLayerTreeHostScrollTest {
+ public:
+ // Setup 3 Layers:
+ // 1) bottom_ which has a non-fast region in the bottom-right.
+ // 2) middle_scrollable_ which is scrollable.
+ // 3) top_ which has a non-fast region in the top-left and is offset by
+ // |middle_scrollable_|'s scroll offset.
+ void SetupTree() override {
+ LayerListLayerTreeHostScrollTest::SetupTree();
+
+ fake_content_layer_client_.set_bounds(root()->bounds());
+
+ std::vector<scoped_refptr<Layer>> layer_list;
+
+ bottom_ = FakePictureLayer::Create(&fake_content_layer_client_);
+ bottom_->SetElementId(LayerIdToElementIdForTesting(bottom_->id()));
+ bottom_->SetBounds(gfx::Size(100, 100));
+ bottom_->SetNonFastScrollableRegion(Region(gfx::Rect(50, 50, 50, 50)));
+ bottom_->SetHitTestable(true);
+ bottom_->SetTransformTreeIndex(kRootNodeId);
+ bottom_->SetEffectTreeIndex(kRootNodeId);
+ bottom_->SetScrollTreeIndex(kRootNodeId);
+ bottom_->SetClipTreeIndex(kRootNodeId);
+ bottom_->set_property_tree_sequence_number(
+ root()->property_tree_sequence_number());
+ layer_list.push_back(bottom_);
+
+ auto& scroll_tree = layer_tree_host()->property_trees()->scroll_tree;
+ auto& scroll_node =
+ *scroll_tree.Node(scroll_tree.Insert(ScrollNode(), kRootNodeId));
+ scroll_node.transform_id = kRootNodeId;
+ middle_scrollable_ = FakePictureLayer::Create(&fake_content_layer_client_);
+ middle_scrollable_->SetElementId(
+ LayerIdToElementIdForTesting(middle_scrollable_->id()));
+ scroll_node.element_id = middle_scrollable_->element_id();
+ scroll_node.scrollable = true;
+ scroll_node.bounds = gfx::Size(100, 200);
+ scroll_node.container_bounds = gfx::Size(100, 100);
+ middle_scrollable_->SetBounds(gfx::Size(100, 100));
+ middle_scrollable_->SetIsDrawable(true);
+ middle_scrollable_->SetScrollable(gfx::Size(100, 200));
+ middle_scrollable_->SetHitTestable(true);
+ middle_scrollable_->SetTransformTreeIndex(kRootNodeId);
+ middle_scrollable_->SetEffectTreeIndex(kRootNodeId);
+ middle_scrollable_->SetScrollTreeIndex(scroll_node.id);
+ middle_scrollable_->SetClipTreeIndex(kRootNodeId);
+ middle_scrollable_->set_property_tree_sequence_number(
+ root()->property_tree_sequence_number());
+ layer_list.push_back(middle_scrollable_);
+
+ top_ = FakePictureLayer::Create(&fake_content_layer_client_);
+ top_->SetElementId(LayerIdToElementIdForTesting(top_->id()));
+ top_->SetBounds(gfx::Size(100, 100));
+ top_->SetNonFastScrollableRegion(Region(gfx::Rect(0, 0, 50, 50)));
+ top_->SetHitTestable(true);
+ top_->SetTransformTreeIndex(kRootNodeId);
+ top_->SetEffectTreeIndex(kRootNodeId);
+ top_->SetScrollTreeIndex(scroll_node.id);
+ top_->SetClipTreeIndex(kRootNodeId);
+ top_->set_property_tree_sequence_number(
+ root()->property_tree_sequence_number());
+
+ layer_list.push_back(top_);
+ root()->SetChildLayerList(std::move(layer_list));
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
+ // The top-left hit should immediately hit the top layer's non-fast region
+ // which forces main-thread scrolling.
+ auto top_left_status = impl->ScrollBegin(
+ BeginState(gfx::Point(20, 20)).get(), InputHandler::TOUCHSCREEN);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, top_left_status.thread);
+ EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
+ top_left_status.main_thread_scrolling_reasons);
+
+ // The top-right hit should hit the top layer but not the non-fast region so
+ // the scroll should continue to scroll on the impl.
+ InputHandler::ScrollStatus top_right_status = impl->ScrollBegin(
+ BeginState(gfx::Point(80, 20)).get(), InputHandler::TOUCHSCREEN);
+ EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, top_right_status.thread);
+ EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
+ top_right_status.main_thread_scrolling_reasons);
+
+ // The bottom-right should hit the bottom layer's non-fast region. Though
+ // the middle layer is a composited scroller and is hit first, we cannot do
+ // a fast scroll because an ancestor on the scroll chain has hit a non-fast
+ // region.
+ InputHandler::ScrollStatus bottom_right_status = impl->ScrollBegin(
+ BeginState(gfx::Point(80, 80)).get(), InputHandler::TOUCHSCREEN);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, bottom_right_status.thread);
+ EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
+ bottom_right_status.main_thread_scrolling_reasons);
+
+ EndTest();
+ }
+
+ void AfterTest() override {}
+
+ private:
+ FakeContentLayerClient fake_content_layer_client_;
+ scoped_refptr<Layer> bottom_;
+ scoped_refptr<Layer> middle_scrollable_;
+ scoped_refptr<Layer> top_;
+};
+
+SINGLE_THREAD_TEST_F(NonScrollingNonFastScrollableRegion);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index fbd783c9798..fe75edcd991 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -89,7 +89,6 @@ LayerTreeImpl::LayerTreeImpl(
external_page_scale_factor_(1.f),
device_scale_factor_(1.f),
painted_device_scale_factor_(1.f),
- content_source_id_(0),
elastic_overscroll_(elastic_overscroll),
layers_(new OwnedLayerImplList),
needs_update_draw_properties_(true),
@@ -484,8 +483,6 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->SetRasterColorSpace(raster_color_space_id_, raster_color_space_);
target_tree->elastic_overscroll()->PushPendingToActive();
- target_tree->set_content_source_id(content_source_id());
-
target_tree->set_painted_device_scale_factor(painted_device_scale_factor());
target_tree->SetDeviceScaleFactor(device_scale_factor());
target_tree->SetDeviceViewportSize(device_viewport_size_);
@@ -1290,7 +1287,6 @@ bool LayerTreeImpl::UpdateDrawProperties(
InnerViewportScrollLayer(), OuterViewportScrollLayer(),
elastic_overscroll()->Current(IsActiveTree()),
OverscrollElasticityElementId(), max_texture_size(),
- settings().layer_transforms_should_scale_layer_contents,
&render_surface_list_, &property_trees_, PageScaleTransformNode());
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
if (const char* client_name = GetClientNameForMetrics()) {
@@ -1456,6 +1452,18 @@ LayerImpl* LayerTreeImpl::LayerById(int id) const {
return iter != layer_id_map_.end() ? iter->second : nullptr;
}
+// TODO(masonfreed): If this shows up on profiles, this could use
+// a layer_element_map_ approach similar to LayerById().
+LayerImpl* LayerTreeImpl::LayerByElementId(ElementId element_id) const {
+ auto it = std::find_if(layer_list_.rbegin(), layer_list_.rend(),
+ [&element_id](LayerImpl* layer_impl) {
+ return layer_impl->element_id() == element_id;
+ });
+ if (it == layer_list_.rend())
+ return nullptr;
+ return *it;
+}
+
LayerImpl* LayerTreeImpl::ScrollableLayerByElementId(
ElementId element_id) const {
auto iter = element_id_to_scrollable_layer_.find(element_id);
@@ -1482,7 +1490,7 @@ void LayerTreeImpl::AddLayerShouldPushProperties(LayerImpl* layer) {
DCHECK(!IsActiveTree()) << "The active tree does not push layer properties";
// TODO(crbug.com/303943): PictureLayerImpls always push properties so should
// not go into this set or we'd push them twice.
- DCHECK(!base::ContainsValue(picture_layers_, layer));
+ DCHECK(!base::Contains(picture_layers_, layer));
layers_that_should_push_properties_.insert(layer);
}
@@ -1503,7 +1511,7 @@ void LayerTreeImpl::UnregisterLayer(LayerImpl* layer) {
// These manage ownership of the LayerImpl.
void LayerTreeImpl::AddLayer(std::unique_ptr<LayerImpl> layer) {
- DCHECK(!base::ContainsValue(*layers_, layer));
+ DCHECK(!base::Contains(*layers_, layer));
DCHECK(layer);
layers_->push_back(std::move(layer));
set_needs_update_draw_properties();
@@ -1862,7 +1870,7 @@ void LayerTreeImpl::ProcessUIResourceRequestQueue() {
}
void LayerTreeImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
- DCHECK(!base::ContainsValue(picture_layers_, layer));
+ DCHECK(!base::Contains(picture_layers_, layer));
picture_layers_.push_back(layer);
}
@@ -1870,6 +1878,23 @@ void LayerTreeImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
auto it = std::find(picture_layers_.begin(), picture_layers_.end(), layer);
DCHECK(it != picture_layers_.end());
picture_layers_.erase(it);
+
+ // Make sure that |picture_layers_with_paint_worklets_| doesn't get left with
+ // dead layers. They should already have been removed (via calling
+ // NotifyLayerHasPaintWorkletsChanged) before the layer was unregistered.
+ DCHECK(!picture_layers_with_paint_worklets_.contains(layer));
+}
+
+void LayerTreeImpl::NotifyLayerHasPaintWorkletsChanged(PictureLayerImpl* layer,
+ bool has_worklets) {
+ if (has_worklets) {
+ auto insert_pair = picture_layers_with_paint_worklets_.insert(layer);
+ DCHECK(insert_pair.second);
+ } else {
+ auto it = picture_layers_with_paint_worklets_.find(layer);
+ DCHECK(it != picture_layers_with_paint_worklets_.end());
+ picture_layers_with_paint_worklets_.erase(it);
+ }
}
void LayerTreeImpl::RegisterScrollbar(ScrollbarLayerImplBase* scrollbar_layer) {
@@ -2179,8 +2204,10 @@ LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPoint(
struct FindTouchEventLayerFunctor {
bool operator()(LayerImpl* layer) const {
+ if (!layer->has_touch_action_regions())
+ return false;
return PointHitsRegion(screen_space_point, layer->ScreenSpaceTransform(),
- layer->touch_action_region().region(), layer);
+ layer->GetAllTouchActionRegions(), layer);
}
const gfx::PointF screen_space_point;
};
@@ -2220,6 +2247,28 @@ LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInWheelEventHandlerRegion(
func);
}
+std::vector<const LayerImpl*>
+LayerTreeImpl::FindLayersHitByPointInNonFastScrollableRegion(
+ const gfx::PointF& screen_space_point) {
+ std::vector<const LayerImpl*> layers;
+ if (layer_list_.empty())
+ return layers;
+ if (!UpdateDrawProperties())
+ return layers;
+ for (const auto* layer : *this) {
+ if (layer->non_fast_scrollable_region().IsEmpty())
+ continue;
+ if (!PointHitsLayer(layer, screen_space_point, nullptr))
+ continue;
+ if (PointHitsRegion(screen_space_point, layer->ScreenSpaceTransform(),
+ layer->non_fast_scrollable_region(), layer)) {
+ layers.push_back(layer);
+ }
+ }
+
+ return layers;
+}
+
void LayerTreeImpl::RegisterSelection(const LayerSelection& selection) {
if (selection_ == selection)
return;
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index 21f3f87674a..5efd40a6f8f 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -343,9 +343,6 @@ class CC_EXPORT LayerTreeImpl {
return painted_device_scale_factor_;
}
- void set_content_source_id(uint32_t id) { content_source_id_ = id; }
- uint32_t content_source_id() { return content_source_id_; }
-
void SetLocalSurfaceIdAllocationFromParent(
const viz::LocalSurfaceIdAllocation&
local_surface_id_allocation_from_parent);
@@ -460,6 +457,7 @@ class CC_EXPORT LayerTreeImpl {
gfx::Rect RootScrollLayerDeviceViewportBounds() const;
LayerImpl* LayerById(int id) const;
+ LayerImpl* LayerByElementId(ElementId element_id) const;
LayerImpl* ScrollableLayerByElementId(ElementId element_id) const;
bool IsElementInPropertyTree(ElementId element_id) const;
@@ -545,6 +543,13 @@ class CC_EXPORT LayerTreeImpl {
return picture_layers_;
}
+ void NotifyLayerHasPaintWorkletsChanged(PictureLayerImpl* layer,
+ bool has_worklets);
+ const base::flat_set<PictureLayerImpl*>& picture_layers_with_paint_worklets()
+ const {
+ return picture_layers_with_paint_worklets_;
+ }
+
void RegisterScrollbar(ScrollbarLayerImplBase* scrollbar_layer);
void UnregisterScrollbar(ScrollbarLayerImplBase* scrollbar_layer);
ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const;
@@ -560,6 +565,10 @@ class CC_EXPORT LayerTreeImpl {
LayerImpl* FindLayerThatIsHitByPointInWheelEventHandlerRegion(
const gfx::PointF& screen_space_point);
+ // Return all layers with a hit non-fast scrollable region.
+ std::vector<const LayerImpl*> FindLayersHitByPointInNonFastScrollableRegion(
+ const gfx::PointF& screen_space_point);
+
void RegisterSelection(const LayerSelection& selection);
bool HandleVisibilityChanged() const { return handle_visibility_changed_; }
@@ -704,7 +713,6 @@ class CC_EXPORT LayerTreeImpl {
int raster_color_space_id_ = -1;
gfx::ColorSpace raster_color_space_;
- uint32_t content_source_id_;
viz::LocalSurfaceIdAllocation local_surface_id_allocation_from_parent_;
bool new_local_surface_id_request_ = false;
gfx::Size device_viewport_size_;
@@ -745,6 +753,11 @@ class CC_EXPORT LayerTreeImpl {
std::vector<PictureLayerImpl*> picture_layers_;
+ // After commit (or impl-side invalidation), the LayerTreeHostImpl must walk
+ // all PictureLayerImpls that have PaintWorklets to ensure they are painted.
+ // To avoid unnecessary walking, we track that set here.
+ base::flat_set<PictureLayerImpl*> picture_layers_with_paint_worklets_;
+
base::flat_set<viz::SurfaceRange> surface_layer_ranges_;
// List of render surfaces for the most recently prepared frame.
diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc
index 4dc46346a58..11d6bbc38d7 100644
--- a/chromium/cc/trees/layer_tree_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_impl_unittest.cc
@@ -6,6 +6,7 @@
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_raster_source.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_test_common.h"
#include "cc/trees/clip_node.h"
@@ -18,17 +19,10 @@
namespace cc {
namespace {
-class LayerTreeImplTestSettings : public LayerTreeSettings {
- public:
- LayerTreeImplTestSettings() {
- layer_transforms_should_scale_layer_contents = true;
- }
-};
-
class LayerTreeImplTest : public testing::Test {
public:
- LayerTreeImplTest(
- const LayerTreeSettings& settings = LayerTreeImplTestSettings())
+ explicit LayerTreeImplTest(
+ const LayerTreeSettings& settings = LayerTreeSettings())
: impl_test_(settings) {}
FakeLayerTreeHostImpl& host_impl() const { return *impl_test_.host_impl(); }
@@ -47,7 +41,6 @@ class LayerTreeImplTest : public testing::Test {
render_surface_list_impl_.clear();
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root_layer, root_layer->bounds(), &render_surface_list_impl_);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
}
@@ -2468,6 +2461,61 @@ TEST_F(LayerTreeImplTest, NotPersistentSwapPromisesAreDroppedWhenSwapFails) {
}
}
+TEST_F(LayerTreeImplTest, TrackPictureLayersWithPaintWorklets) {
+ host_impl().CreatePendingTree();
+ LayerTreeImpl* pending_tree = host_impl().pending_tree();
+
+ // Initially there are no layers in the set.
+ EXPECT_EQ(pending_tree->picture_layers_with_paint_worklets().size(), 0u);
+
+ // Add three layers; two with PaintWorklets and one without.
+ std::unique_ptr<PictureLayerImpl> child1_owned =
+ PictureLayerImpl::Create(pending_tree, 2, Layer::LayerMaskType::NOT_MASK);
+ child1_owned->SetBounds(gfx::Size(100, 100));
+ std::unique_ptr<PictureLayerImpl> child2_owned =
+ PictureLayerImpl::Create(pending_tree, 3, Layer::LayerMaskType::NOT_MASK);
+ child2_owned->SetBounds(gfx::Size(100, 100));
+ std::unique_ptr<PictureLayerImpl> child3_owned =
+ PictureLayerImpl::Create(pending_tree, 4, Layer::LayerMaskType::NOT_MASK);
+ child3_owned->SetBounds(gfx::Size(100, 100));
+
+ PictureLayerImpl* child1 = child1_owned.get();
+ PictureLayerImpl* child3 = child3_owned.get();
+
+ root_layer()->test_properties()->AddChild(std::move(child1_owned));
+ root_layer()->test_properties()->AddChild(std::move(child2_owned));
+ root_layer()->test_properties()->AddChild(std::move(child3_owned));
+
+ Region empty_invalidation;
+ scoped_refptr<RasterSource> raster_source1(
+ FakeRasterSource::CreateFilledWithPaintWorklet(child1->bounds()));
+ child1->UpdateRasterSource(raster_source1, &empty_invalidation, nullptr,
+ nullptr);
+ scoped_refptr<RasterSource> raster_source3(
+ FakeRasterSource::CreateFilledWithPaintWorklet(child3->bounds()));
+ child3->UpdateRasterSource(raster_source3, &empty_invalidation, nullptr,
+ nullptr);
+
+ // The set should correctly track which layers are in it.
+ const base::flat_set<PictureLayerImpl*>& layers =
+ pending_tree->picture_layers_with_paint_worklets();
+ EXPECT_EQ(layers.size(), 2u);
+ EXPECT_TRUE(layers.contains(child1));
+ EXPECT_TRUE(layers.contains(child3));
+
+ // Test explicitly removing a layer from the set.
+ scoped_refptr<RasterSource> empty_raster_source(
+ FakeRasterSource::CreateFilled(child1->bounds()));
+ child1->UpdateRasterSource(empty_raster_source, &empty_invalidation, nullptr,
+ nullptr);
+ EXPECT_EQ(layers.size(), 1u);
+ EXPECT_FALSE(layers.contains(child1));
+
+ // Deleting a layer should also cause it to be removed from the set.
+ root_layer()->test_properties()->RemoveChild(child3);
+ EXPECT_EQ(layers.size(), 0u);
+}
+
namespace {
class CommitToPendingTreeLayerTreeImplTestSettings : public LayerTreeSettings {
public:
diff --git a/chromium/cc/trees/layer_tree_settings.cc b/chromium/cc/trees/layer_tree_settings.cc
index 047b36948e7..ce4ba0308eb 100644
--- a/chromium/cc/trees/layer_tree_settings.cc
+++ b/chromium/cc/trees/layer_tree_settings.cc
@@ -24,19 +24,11 @@ SchedulerSettings LayerTreeSettings::ToSchedulerSettings() const {
SchedulerSettings scheduler_settings;
scheduler_settings.main_frame_before_activation_enabled =
main_frame_before_activation_enabled;
- scheduler_settings.timeout_and_draw_when_animation_checkerboards =
- timeout_and_draw_when_animation_checkerboards;
scheduler_settings.using_synchronous_renderer_compositor =
using_synchronous_renderer_compositor;
scheduler_settings.enable_latency_recovery = enable_latency_recovery;
- scheduler_settings.background_frame_interval =
- base::TimeDelta::FromSecondsD(1.0 / background_animation_rate);
scheduler_settings.wait_for_all_pipeline_stages_before_draw =
wait_for_all_pipeline_stages_before_draw;
- scheduler_settings.enable_surface_synchronization =
- enable_surface_synchronization;
- scheduler_settings.compositor_threaded_scrollbar_scrolling =
- compositor_threaded_scrollbar_scrolling;
return scheduler_settings;
}
diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h
index 092fb1b7ea3..d62c52b5326 100644
--- a/chromium/cc/trees/layer_tree_settings.h
+++ b/chromium/cc/trees/layer_tree_settings.h
@@ -62,13 +62,11 @@ class CC_EXPORT LayerTreeSettings {
SkColor solid_color_scrollbar_color = SK_ColorWHITE;
base::TimeDelta scroll_animation_duration_for_testing;
bool timeout_and_draw_when_animation_checkerboards = true;
- bool layer_transforms_should_scale_layer_contents = false;
bool layers_always_allowed_lcd_text = false;
float minimum_contents_scale = 0.0625f;
float low_res_contents_scale_factor = 0.25f;
float top_controls_show_threshold = 0.5f;
float top_controls_hide_threshold = 0.5f;
- double background_animation_rate = 1.0;
gfx::Size default_tile_size;
gfx::Size max_untiled_layer_size;
// If set, indicates the largest tile size we will use for GPU Raster. If not
@@ -97,8 +95,6 @@ class CC_EXPORT LayerTreeSettings {
bool use_rgba_4444 = false;
bool unpremultiply_and_dither_low_bit_depth_tiles = false;
- bool enable_mask_tiling = true;
-
// If set to true, the compositor may selectively defer image decodes to the
// Image Decode Service and raster tiles without images until the decode is
// ready.
diff --git a/chromium/cc/trees/mutator_host.h b/chromium/cc/trees/mutator_host.h
index 03e3ce4d4a0..c52ce403301 100644
--- a/chromium/cc/trees/mutator_host.h
+++ b/chromium/cc/trees/mutator_host.h
@@ -9,7 +9,7 @@
#include "base/callback_forward.h"
#include "base/time/time.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
#include "cc/trees/layer_tree_mutator.h"
#include "cc/trees/mutator_host_client.h"
#include "ui/gfx/geometry/box_f.h"
@@ -131,6 +131,13 @@ class MutatorHost {
virtual bool HasTickingKeyframeModelForTesting(
ElementId element_id) const = 0;
+ virtual void ImplOnlyAutoScrollAnimationCreate(
+ ElementId element_id,
+ const gfx::ScrollOffset& target_offset,
+ const gfx::ScrollOffset& current_offset,
+ float autoscroll_velocity,
+ base::TimeDelta animation_start_offset) = 0;
+
virtual void ImplOnlyScrollAnimationCreate(
ElementId element_id,
const gfx::ScrollOffset& target_offset,
diff --git a/chromium/cc/trees/mutator_host_client.h b/chromium/cc/trees/mutator_host_client.h
index 5d221f3051c..406b10abfc5 100644
--- a/chromium/cc/trees/mutator_host_client.h
+++ b/chromium/cc/trees/mutator_host_client.h
@@ -5,7 +5,7 @@
#ifndef CC_TREES_MUTATOR_HOST_CLIENT_H_
#define CC_TREES_MUTATOR_HOST_CLIENT_H_
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
#include "cc/trees/property_animation_state.h"
#include "cc/trees/target_property.h"
diff --git a/chromium/cc/trees/occlusion_tracker_unittest.cc b/chromium/cc/trees/occlusion_tracker_unittest.cc
index 04827454e5e..638a253ceb6 100644
--- a/chromium/cc/trees/occlusion_tracker_unittest.cc
+++ b/chromium/cc/trees/occlusion_tracker_unittest.cc
@@ -203,7 +203,6 @@ class OcclusionTrackerTest : public testing::Test {
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root, root->bounds(), &render_surface_list_impl_);
- inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
layer_iterator_ = std::make_unique<EffectTreeLayerListIterator>(
diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc
index 5d6b0b82fa1..f91deac77f3 100644
--- a/chromium/cc/trees/property_tree.cc
+++ b/chromium/cc/trees/property_tree.cc
@@ -233,6 +233,8 @@ void TransformTree::UpdateTransforms(int id) {
UpdateNodeAndAncestorsHaveIntegerTranslations(node, parent_node);
UpdateTransformChanged(node, parent_node, source_node);
UpdateNodeAndAncestorsAreAnimatedOrInvertible(node, parent_node);
+
+ DCHECK(!node->needs_local_transform_update);
}
bool TransformTree::IsDescendant(int desc_id, int source_id) const {
@@ -374,7 +376,7 @@ gfx::Vector2dF StickyPositionOffset(TransformTree* tree, TransformNode* node) {
scroll_position -= transform_node->snap_amount;
}
- gfx::RectF clip = constraint.constraint_box_rect;
+ gfx::Rect clip = constraint.constraint_box_rect;
clip.Offset(scroll_position.x(), scroll_position.y());
// The clip region may need to be offset by the outer viewport bounds, e.g. if
@@ -831,7 +833,6 @@ void EffectTree::UpdateHasMaskingChild(EffectNode* node,
// when we actually encounter a masking child.
node->has_masking_child = false;
if (node->blend_mode == SkBlendMode::kDstIn) {
- DCHECK(parent_node->HasRenderSurface());
parent_node->has_masking_child = true;
}
}
@@ -850,16 +851,10 @@ void EffectTree::UpdateSurfaceContentsScale(EffectNode* effect_node) {
if (transform_node->in_subtree_of_page_scale_layer)
layer_scale_factor *= transform_tree.page_scale_factor();
- // Note: Copy requests currently expect transform to effect output size.
- bool use_transform_for_contents_scale =
- property_trees()->can_adjust_raster_scales ||
- effect_node->has_copy_request;
const gfx::Vector2dF old_scale = effect_node->surface_contents_scale;
effect_node->surface_contents_scale =
- use_transform_for_contents_scale
- ? MathUtil::ComputeTransform2dScaleComponents(
- transform_tree.ToScreen(transform_node->id), layer_scale_factor)
- : gfx::Vector2dF(layer_scale_factor, layer_scale_factor);
+ MathUtil::ComputeTransform2dScaleComponents(
+ transform_tree.ToScreen(transform_node->id), layer_scale_factor);
// If surface contents scale changes, draw transforms are no longer valid.
// Invalidates the draw transform cache and updates the clip for the surface.
@@ -1757,7 +1752,6 @@ PropertyTreesCachedData::~PropertyTreesCachedData() = default;
PropertyTrees::PropertyTrees()
: needs_rebuild(true),
- can_adjust_raster_scales(true),
changed(false),
full_tree_damaged(false),
sequence_number(0),
@@ -1785,7 +1779,6 @@ bool PropertyTrees::operator==(const PropertyTrees& other) const {
full_tree_damaged == other.full_tree_damaged &&
is_main_thread == other.is_main_thread &&
is_active == other.is_active &&
- can_adjust_raster_scales == other.can_adjust_raster_scales &&
sequence_number == other.sequence_number;
}
@@ -1800,7 +1793,6 @@ PropertyTrees& PropertyTrees::operator=(const PropertyTrees& from) {
needs_rebuild = from.needs_rebuild;
changed = from.changed;
full_tree_damaged = from.full_tree_damaged;
- can_adjust_raster_scales = from.can_adjust_raster_scales;
sequence_number = from.sequence_number;
is_main_thread = from.is_main_thread;
is_active = from.is_active;
@@ -1830,7 +1822,6 @@ void PropertyTrees::clear() {
needs_rebuild = true;
full_tree_damaged = false;
changed = false;
- can_adjust_raster_scales = true;
sequence_number++;
#if DCHECK_IS_ON()
@@ -2077,17 +2068,6 @@ CombinedAnimationScale PropertyTrees::GetAnimationScales(
&cached_data_.animation_scales[transform_node_id];
if (animation_scales->update_number !=
cached_data_.transform_tree_update_number) {
- if (!layer_tree_impl->settings()
- .layer_transforms_should_scale_layer_contents) {
- animation_scales->update_number =
- cached_data_.transform_tree_update_number;
- animation_scales->combined_maximum_animation_target_scale = kNotScaled;
- animation_scales->combined_starting_animation_scale = kNotScaled;
- return CombinedAnimationScale(
- animation_scales->combined_maximum_animation_target_scale,
- animation_scales->combined_starting_animation_scale);
- }
-
TransformNode* node = transform_tree.Node(transform_node_id);
TransformNode* parent_node = transform_tree.parent(node);
bool ancestor_is_animating_scale = false;
diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h
index f61d2c26a84..75b972dd86c 100644
--- a/chromium/cc/trees/property_tree.h
+++ b/chromium/cc/trees/property_tree.h
@@ -15,8 +15,8 @@
#include "cc/base/synced_property.h"
#include "cc/cc_export.h"
#include "cc/layers/layer_sticky_position_constraint.h"
+#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
-#include "cc/trees/element_id.h"
#include "cc/trees/mutator_host_client.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
@@ -631,7 +631,6 @@ class CC_EXPORT PropertyTrees final {
ClipTree clip_tree;
ScrollTree scroll_tree;
bool needs_rebuild;
- bool can_adjust_raster_scales;
// Change tracking done on property trees needs to be preserved across commits
// (when they are not rebuild). We cache a global bool which stores whether
// we did any change tracking so that we can skip copying the change status
diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc
index bd5882ee4f9..44a2033de9a 100644
--- a/chromium/cc/trees/property_tree_builder.cc
+++ b/chromium/cc/trees/property_tree_builder.cc
@@ -180,6 +180,14 @@ static LayerImpl* ClipParent(LayerImpl* layer) {
return layer->test_properties()->clip_parent;
}
+static bool HasClipRect(Layer* layer) {
+ return !layer->clip_rect().IsEmpty();
+}
+
+static bool HasClipRect(LayerImpl* layer) {
+ return false;
+}
+
static inline const FilterOperations& Filters(Layer* layer) {
return layer->filters();
}
@@ -204,15 +212,6 @@ static bool HasRoundedCorner(LayerImpl* layer) {
return !layer->test_properties()->rounded_corner_bounds.IsEmpty();
}
-static gfx::RRectF RoundedCornerBounds(Layer* layer) {
- return gfx::RRectF(gfx::RectF(gfx::Rect(layer->bounds())),
- layer->corner_radii());
-}
-
-static gfx::RRectF RoundedCornerBounds(LayerImpl* layer) {
- return layer->test_properties()->rounded_corner_bounds;
-}
-
static PictureLayer* MaskLayer(Layer* layer) {
return layer->mask_layer();
}
@@ -310,9 +309,30 @@ static int GetTransformParent(const DataForRecursion& data, LayerType* layer) {
}
template <typename LayerType>
+static bool LayerClipsSubtreeToItsBounds(LayerType* layer) {
+ return layer->masks_to_bounds() || MaskLayer(layer);
+}
+
+template <typename LayerType>
static bool LayerClipsSubtree(LayerType* layer) {
- return layer->masks_to_bounds() || MaskLayer(layer) ||
- HasRoundedCorner(layer);
+ return LayerClipsSubtreeToItsBounds(layer) || HasRoundedCorner(layer) ||
+ HasClipRect(layer);
+}
+
+gfx::RectF EffectiveClipRect(Layer* layer) {
+ return layer->EffectiveClipRect();
+}
+
+gfx::RectF EffectiveClipRect(LayerImpl* layer) {
+ return gfx::RectF(gfx::PointF(), gfx::SizeF(layer->bounds()));
+}
+
+static gfx::RRectF RoundedCornerBounds(Layer* layer) {
+ return gfx::RRectF(EffectiveClipRect(layer), layer->corner_radii());
+}
+
+static gfx::RRectF RoundedCornerBounds(LayerImpl* layer) {
+ return layer->test_properties()->rounded_corner_bounds;
}
template <typename LayerType>
@@ -355,6 +375,12 @@ static inline bool HasLatestSequenceNumber(const LayerImpl*, int) {
return true;
}
+static inline void SetHasClipNode(Layer* layer, bool val) {
+ layer->SetHasClipNode(val);
+}
+
+static inline void SetHasClipNode(LayerImpl* layer, bool val) {}
+
template <typename LayerType>
void PropertyTreeBuilderContext<LayerType>::AddClipNodeIfNeeded(
const DataForRecursion& data_from_ancestor,
@@ -376,8 +402,11 @@ void PropertyTreeBuilderContext<LayerType>::AddClipNodeIfNeeded(
data_for_children->clip_tree_parent = parent_id;
} else {
ClipNode node;
- node.clip = gfx::RectF(gfx::PointF() + layer->offset_to_transform_parent(),
- gfx::SizeF(layer->bounds()));
+ node.clip = EffectiveClipRect(layer);
+
+ // Move the clip bounds so that it is relative to the transform parent.
+ node.clip += layer->offset_to_transform_parent();
+
node.transform_id = created_transform_node
? data_for_children->transform_tree_parent
: GetTransformParent(data_from_ancestor, layer);
@@ -391,6 +420,7 @@ void PropertyTreeBuilderContext<LayerType>::AddClipNodeIfNeeded(
data_for_children->clip_tree_parent = clip_tree_.Insert(node, parent_id);
}
+ SetHasClipNode(layer, requires_node);
layer->SetClipTreeIndex(data_for_children->clip_tree_parent);
}
@@ -797,6 +827,14 @@ static inline const base::Optional<gfx::RRectF>& BackdropFilterBounds(
return layer->test_properties()->backdrop_filter_bounds;
}
+static inline ElementId BackdropMaskElementId(Layer* layer) {
+ return layer->backdrop_mask_element_id();
+}
+
+static inline ElementId BackdropMaskElementId(LayerImpl* layer) {
+ return layer->test_properties()->backdrop_mask_element_id;
+}
+
static inline float BackdropFilterQuality(Layer* layer) {
return layer->backdrop_filter_quality();
}
@@ -821,6 +859,14 @@ static inline bool HasCopyRequest(LayerImpl* layer) {
return !layer->test_properties()->copy_requests.empty();
}
+static inline int MirrorCount(Layer* layer) {
+ return layer->mirror_count();
+}
+
+static inline int MirrorCount(LayerImpl* layer) {
+ return 0;
+}
+
static inline bool PropertyChanged(Layer* layer) {
return layer->subtree_property_changed();
}
@@ -933,6 +979,10 @@ RenderSurfaceReason ComputeRenderSurfaceReason(const MutatorHost& mutator_host,
if (HasCopyRequest(layer))
return RenderSurfaceReason::kCopyRequest;
+ // If the layer is mirrored.
+ if (MirrorCount(layer))
+ return RenderSurfaceReason::kMirrored;
+
return RenderSurfaceReason::kNone;
}
@@ -1040,6 +1090,7 @@ bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded(
node->backdrop_filters = BackdropFilters(layer);
node->backdrop_filter_bounds = BackdropFilterBounds(layer);
node->backdrop_filter_quality = BackdropFilterQuality(layer);
+ node->backdrop_mask_element_id = BackdropMaskElementId(layer);
node->filters_origin = FiltersOrigin(layer);
node->trilinear_filtering = TrilinearFiltering(layer);
node->has_potential_opacity_animation = has_potential_opacity_animation;
diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h
index 10a58a32998..0fe7a90fe3f 100644
--- a/chromium/cc/trees/proxy.h
+++ b/chromium/cc/trees/proxy.h
@@ -39,10 +39,6 @@ class CC_EXPORT Proxy {
virtual bool IsStarted() const = 0;
- // This function retruns true if the commits go directly to active tree by
- // skipping commit to pending tree.
- virtual bool CommitToActiveTree() const = 0;
-
virtual void SetLayerTreeFrameSink(
LayerTreeFrameSink* layer_tree_frame_sink) = 0;
virtual void ReleaseLayerTreeFrameSink() = 0;
diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc
index cdfd8d3a135..2e69eddc64e 100644
--- a/chromium/cc/trees/proxy_impl.cc
+++ b/chromium/cc/trees/proxy_impl.cc
@@ -191,7 +191,9 @@ void ProxyImpl::BeginMainFrameAbortedOnImpl(
DCHECK(IsImplThread());
DCHECK(scheduler_->CommitPending());
- host_impl_->BeginMainFrameAborted(reason, std::move(swap_promises));
+ host_impl_->BeginMainFrameAborted(
+ reason, std::move(swap_promises),
+ scheduler_->last_dispatched_begin_main_frame_args());
scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time);
scheduler_->BeginMainFrameAborted(reason);
}
@@ -365,7 +367,7 @@ void ProxyImpl::PostAnimationEventsToMainThreadOnImplThread(
DCHECK(IsImplThread());
MainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&ProxyMain::SetAnimationEvents,
- proxy_main_weak_ptr_, base::Passed(&events)));
+ proxy_main_weak_ptr_, std::move(events)));
}
size_t ProxyImpl::CompositedAnimationsCount() const {
@@ -388,6 +390,14 @@ bool ProxyImpl::IsInsideDraw() {
return inside_draw_;
}
+bool ProxyImpl::IsBeginMainFrameExpected() {
+ // Check whether the main-thread has requested for updates. If main-thread has
+ // not responded to a previously dispatched BeginMainFrame, then assume that
+ // main-thread would want to produce an update for the current frame too.
+ return scheduler_->needs_begin_main_frame() ||
+ scheduler_->IsBeginMainFrameSent();
+}
+
void ProxyImpl::RenewTreePriority() {
DCHECK(IsImplThread());
const bool user_interaction_in_progress =
@@ -495,6 +505,8 @@ void ProxyImpl::DidPresentCompositorFrameOnImplThread(
FROM_HERE, base::BindOnce(&ProxyMain::DidPresentCompositorFrame,
proxy_main_weak_ptr_, frame_token,
std::move(callbacks), feedback));
+ if (scheduler_)
+ scheduler_->DidPresentCompositorFrame(frame_token, feedback.timestamp);
}
void ProxyImpl::NotifyAnimationWorkletStateChange(
@@ -512,6 +524,12 @@ void ProxyImpl::NotifyAnimationWorkletStateChange(
tree_type);
}
+void ProxyImpl::NotifyPaintWorkletStateChange(
+ Scheduler::PaintWorkletState state) {
+ DCHECK(IsImplThread());
+ scheduler_->NotifyPaintWorkletStateChange(state);
+}
+
bool ProxyImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
DCHECK(IsImplThread());
return host_impl_->WillBeginImplFrame(args);
@@ -551,8 +569,8 @@ void ProxyImpl::ScheduledActionSendBeginMainFrame(
MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&ProxyMain::BeginMainFrame, proxy_main_weak_ptr_,
- base::Passed(&begin_main_frame_state)));
- host_impl_->DidSendBeginMainFrame();
+ std::move(begin_main_frame_state)));
+ host_impl_->DidSendBeginMainFrame(args);
devtools_instrumentation::DidRequestMainThreadFrame(layer_tree_host_id_);
}
@@ -685,6 +703,8 @@ DrawResult ProxyImpl::DrawInternal(bool forced_draw) {
LayerTreeHostImpl::FrameData frame;
frame.begin_frame_ack = scheduler_->CurrentBeginFrameAckForActiveTree();
+ frame.origin_begin_main_frame_args =
+ scheduler_->last_activate_origin_frame_args();
bool draw_frame = false;
DrawResult result;
@@ -696,9 +716,11 @@ DrawResult ProxyImpl::DrawInternal(bool forced_draw) {
}
if (draw_frame) {
- if (host_impl_->DrawLayers(&frame))
+ if (host_impl_->DrawLayers(&frame)) {
+ DCHECK_NE(frame.frame_token, 0u);
// Drawing implies we submitted a frame to the LayerTreeFrameSink.
- scheduler_->DidSubmitCompositorFrame();
+ scheduler_->DidSubmitCompositorFrame(frame.frame_token);
+ }
result = DRAW_SUCCESS;
} else {
DCHECK_NE(DRAW_SUCCESS, result);
@@ -709,7 +731,7 @@ DrawResult ProxyImpl::DrawInternal(bool forced_draw) {
bool start_ready_animations = draw_frame;
host_impl_->UpdateAnimationState(start_ready_animations);
- // Tell the main thread that the the newly-commited frame was drawn.
+ // Tell the main thread that the newly-commited frame was drawn.
if (next_frame_is_newly_committed_frame_) {
next_frame_is_newly_committed_frame_ = false;
MainThreadTaskRunner()->PostTask(
diff --git a/chromium/cc/trees/proxy_impl.h b/chromium/cc/trees/proxy_impl.h
index 62636b88386..d8222df2013 100644
--- a/chromium/cc/trees/proxy_impl.h
+++ b/chromium/cc/trees/proxy_impl.h
@@ -94,6 +94,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
void PostAnimationEventsToMainThreadOnImplThread(
std::unique_ptr<MutatorEvents> events) override;
bool IsInsideDraw() override;
+ bool IsBeginMainFrameExpected() override;
void RenewTreePriority() override;
void PostDelayedAnimationTaskOnImplThread(base::OnceClosure task,
base::TimeDelta delay) override;
@@ -112,6 +113,8 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
void NotifyAnimationWorkletStateChange(
AnimationWorkletMutationState state,
ElementListType element_list_type) override;
+ void NotifyPaintWorkletStateChange(
+ Scheduler::PaintWorkletState state) override;
// SchedulerClient implementation
bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override;
diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc
index 20299713e6a..dc7b697ae2b 100644
--- a/chromium/cc/trees/proxy_main.cc
+++ b/chromium/cc/trees/proxy_main.cc
@@ -39,9 +39,7 @@ ProxyMain::ProxyMain(LayerTreeHost* layer_tree_host,
commit_waits_for_activation_(false),
started_(false),
defer_main_frame_update_(false),
- defer_commits_(true),
- frame_sink_bound_weak_factory_(this),
- weak_factory_(this) {
+ defer_commits_(true) {
TRACE_EVENT0("cc", "ProxyMain::ProxyMain");
DCHECK(task_runner_provider_);
DCHECK(IsMainThread());
@@ -157,7 +155,7 @@ void ProxyMain::BeginMainFrame(
base::Unretained(proxy_impl_.get()),
CommitEarlyOutReason::ABORTED_NOT_VISIBLE,
begin_main_frame_start_time,
- base::Passed(&empty_swap_promises)));
+ std::move(empty_swap_promises)));
return;
}
@@ -188,7 +186,7 @@ void ProxyMain::BeginMainFrame(
base::Unretained(proxy_impl_.get()),
CommitEarlyOutReason::ABORTED_DEFERRED_MAIN_FRAME_UPDATE,
begin_main_frame_start_time,
- base::Passed(&empty_swap_promises)));
+ std::move(empty_swap_promises)));
// When we stop deferring main frame updates, we should resume any
// previously requested pipeline stages.
deferred_final_pipeline_stage_ =
@@ -202,11 +200,22 @@ void ProxyMain::BeginMainFrame(
current_pipeline_stage_ = ANIMATE_PIPELINE_STAGE;
- // Synchronizes scroll offsets and page scale deltas (for pinch zoom) from the
- // compositor thread thread to the main thread for both cc and and its
- // client (e.g. Blink).
- layer_tree_host_->ApplyScrollAndScale(
- begin_main_frame_state->scroll_info.get());
+ // Check now if we should stop deferring commits due to a timeout. We
+ // may also stop deferring in BeginMainFrame, but maintain the status
+ // from this point to keep scroll in sync.
+ if (defer_commits_ && base::TimeTicks::Now() > commits_restart_time_) {
+ StopDeferringCommits(PaintHoldingCommitTrigger::kTimeout);
+ }
+ skip_commit |= defer_commits_;
+
+ if (!skip_commit) {
+ // Synchronizes scroll offsets and page scale deltas (for pinch zoom) from
+ // the compositor thread to the main thread for both cc and and its client
+ // (e.g. Blink). Do not do this if we explicitly plan to not commit the
+ // layer tree, to prevent scroll offsets getting out of sync.
+ layer_tree_host_->ApplyScrollAndScale(
+ begin_main_frame_state->scroll_info.get());
+ }
layer_tree_host_->WillBeginMainFrame();
layer_tree_host_->RecordStartOfFrameMetrics();
@@ -230,14 +239,10 @@ void ProxyMain::BeginMainFrame(
// what this does.
layer_tree_host_->RequestMainFrameUpdate();
- // Check now if we should stop deferring commits
- if (defer_commits_ && base::TimeTicks::Now() > commits_restart_time_) {
- StopDeferringCommits(PaintHoldingCommitTrigger::kTimeout);
- }
-
- // At this point the main frame may have deferred commits to avoid committing
- // right now, or we may be deferring commits but not deferring main
- // frame updates.
+ // At this point the main frame may have deferred main frame updates to
+ // avoid committing right now, or we may be deferring commits but not
+ // deferring main frame updates. Either may have changed the status
+ // of the defer... flags, so re-evaluate skip_commit.
skip_commit |= defer_main_frame_update_ || defer_commits_;
if (skip_commit) {
@@ -252,7 +257,7 @@ void ProxyMain::BeginMainFrame(
base::Unretained(proxy_impl_.get()),
CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT,
begin_main_frame_start_time,
- base::Passed(&empty_swap_promises)));
+ std::move(empty_swap_promises)));
// We intentionally don't report CommitComplete() here since it was aborted
// prematurely and we're waiting to do another commit in the future.
// When we stop deferring commits, we should resume any previously requested
@@ -295,11 +300,11 @@ void ProxyMain::BeginMainFrame(
std::vector<std::unique_ptr<SwapPromise>> swap_promises =
layer_tree_host_->GetSwapPromiseManager()->TakeSwapPromises();
ImplThreadTaskRunner()->PostTask(
- FROM_HERE, base::BindOnce(&ProxyImpl::BeginMainFrameAbortedOnImpl,
- base::Unretained(proxy_impl_.get()),
- CommitEarlyOutReason::FINISHED_NO_UPDATES,
- begin_main_frame_start_time,
- base::Passed(&swap_promises)));
+ FROM_HERE,
+ base::BindOnce(&ProxyImpl::BeginMainFrameAbortedOnImpl,
+ base::Unretained(proxy_impl_.get()),
+ CommitEarlyOutReason::FINISHED_NO_UPDATES,
+ begin_main_frame_start_time, std::move(swap_promises)));
// Although the commit is internally aborted, this is because it has been
// detected to be a no-op. From the perspective of an embedder, this commit
@@ -315,7 +320,7 @@ void ProxyMain::BeginMainFrame(
ui::LatencyInfo new_latency_info(ui::SourceEventType::FRAME);
new_latency_info.AddLatencyNumberWithTimestamp(
ui::LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT,
- begin_main_frame_state->begin_frame_args.frame_time, 1);
+ begin_main_frame_state->begin_frame_args.frame_time);
layer_tree_host_->QueueSwapPromise(
std::make_unique<LatencyInfoSwapPromise>(new_latency_info));
@@ -365,12 +370,6 @@ bool ProxyMain::IsStarted() const {
return started_;
}
-bool ProxyMain::CommitToActiveTree() const {
- // With ProxyMain, we use a pending tree and activate it once it's ready to
- // draw to allow input to modify the active tree and draw during raster.
- return false;
-}
-
void ProxyMain::SetLayerTreeFrameSink(
LayerTreeFrameSink* layer_tree_frame_sink) {
ImplThreadTaskRunner()->PostTask(
diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h
index 7b110c08a7d..515f1e10de9 100644
--- a/chromium/cc/trees/proxy_main.h
+++ b/chromium/cc/trees/proxy_main.h
@@ -72,7 +72,6 @@ class CC_EXPORT ProxyMain : public Proxy {
private:
// Proxy implementation.
bool IsStarted() const override;
- bool CommitToActiveTree() const override;
void SetLayerTreeFrameSink(
LayerTreeFrameSink* layer_tree_frame_sink) override;
void SetVisible(bool visible) override;
@@ -156,9 +155,9 @@ class CC_EXPORT ProxyMain : public Proxy {
// WeakPtrs generated by this factory will be invalidated when
// LayerTreeFrameSink is released.
- base::WeakPtrFactory<ProxyMain> frame_sink_bound_weak_factory_;
+ base::WeakPtrFactory<ProxyMain> frame_sink_bound_weak_factory_{this};
- base::WeakPtrFactory<ProxyMain> weak_factory_;
+ base::WeakPtrFactory<ProxyMain> weak_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/trees/scroll_node.cc b/chromium/cc/trees/scroll_node.cc
index 69b7b3318f5..50227da93d4 100644
--- a/chromium/cc/trees/scroll_node.cc
+++ b/chromium/cc/trees/scroll_node.cc
@@ -7,7 +7,7 @@
#include "cc/base/math_util.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/layers/layer.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
#include "cc/trees/property_tree.h"
#include "base/trace_event/traced_value.h"
diff --git a/chromium/cc/trees/scroll_node.h b/chromium/cc/trees/scroll_node.h
index de9f9343c8d..1d2e6fa789e 100644
--- a/chromium/cc/trees/scroll_node.h
+++ b/chromium/cc/trees/scroll_node.h
@@ -9,8 +9,8 @@
#include "cc/cc_export.h"
#include "cc/input/overscroll_behavior.h"
#include "cc/input/scroll_snap_data.h"
+#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
-#include "cc/trees/element_id.h"
#include "ui/gfx/geometry/size.h"
namespace base {
diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc
index d74fe26e408..0bc215ea7c4 100644
--- a/chromium/cc/trees/single_thread_proxy.cc
+++ b/chromium/cc/trees/single_thread_proxy.cc
@@ -27,6 +27,7 @@
#include "cc/trees/scoped_abort_remaining_swap_promises.h"
#include "components/viz/common/frame_sinks/delay_based_time_source.h"
#include "components/viz/common/gpu/context_provider.h"
+#include "ui/gfx/presentation_feedback.h"
namespace cc {
@@ -56,9 +57,7 @@ SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host,
inside_synchronous_composite_(false),
needs_impl_frame_(false),
layer_tree_frame_sink_creation_requested_(false),
- layer_tree_frame_sink_lost_(true),
- frame_sink_bound_weak_factory_(this),
- weak_factory_(this) {
+ layer_tree_frame_sink_lost_(true) {
TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
DCHECK(task_runner_provider_);
DCHECK(task_runner_provider_->IsMainThread());
@@ -75,7 +74,7 @@ void SingleThreadProxy::Start() {
host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
if (settings.single_thread_proxy_scheduler && !scheduler_on_impl_thread_) {
SchedulerSettings scheduler_settings(settings.ToSchedulerSettings());
- scheduler_settings.commit_to_active_tree = CommitToActiveTree();
+ scheduler_settings.commit_to_active_tree = true;
std::unique_ptr<CompositorTimingHistory> compositor_timing_history(
new CompositorTimingHistory(
@@ -102,12 +101,6 @@ bool SingleThreadProxy::IsStarted() const {
return !!host_impl_;
}
-bool SingleThreadProxy::CommitToActiveTree() const {
- // With SingleThreadProxy we skip the pending tree and commit directly to the
- // active tree.
- return true;
-}
-
void SingleThreadProxy::SetVisible(bool visible) {
TRACE_EVENT1("cc", "SingleThreadProxy::SetVisible", "visible", visible);
DebugScopedSetImplThread impl(task_runner_provider_);
@@ -436,6 +429,10 @@ bool SingleThreadProxy::IsInsideDraw() {
return inside_draw_;
}
+bool SingleThreadProxy::IsBeginMainFrameExpected() {
+ return true;
+}
+
void SingleThreadProxy::DidActivateSyncTree() {
CommitComplete();
}
@@ -525,6 +522,11 @@ void SingleThreadProxy::DidPresentCompositorFrameOnImplThread(
const gfx::PresentationFeedback& feedback) {
layer_tree_host_->DidPresentCompositorFrame(frame_token, std::move(callbacks),
feedback);
+
+ if (scheduler_on_impl_thread_) {
+ scheduler_on_impl_thread_->DidPresentCompositorFrame(frame_token,
+ feedback.timestamp);
+ }
}
void SingleThreadProxy::NotifyAnimationWorkletStateChange(
@@ -533,6 +535,12 @@ void SingleThreadProxy::NotifyAnimationWorkletStateChange(
layer_tree_host_->NotifyAnimationWorkletStateChange(state, element_list_type);
}
+void SingleThreadProxy::NotifyPaintWorkletStateChange(
+ Scheduler::PaintWorkletState state) {
+ // Off-Thread PaintWorklet is only supported on the threaded compositor.
+ NOTREACHED();
+}
+
void SingleThreadProxy::RequestBeginMainFrameNotExpected(bool new_state) {
if (scheduler_on_impl_thread_) {
scheduler_on_impl_thread_->SetMainThreadWantsBeginMainFrameNotExpected(
@@ -605,6 +613,7 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time,
if (raster) {
LayerTreeHostImpl::FrameData frame;
frame.begin_frame_ack = viz::BeginFrameAck(begin_frame_args, true);
+ frame.origin_begin_main_frame_args = begin_frame_args;
DoComposite(&frame);
}
@@ -666,9 +675,11 @@ DrawResult SingleThreadProxy::DoComposite(LayerTreeHostImpl::FrameData* frame) {
draw_frame = draw_result == DRAW_SUCCESS;
if (draw_frame) {
if (host_impl_->DrawLayers(frame)) {
- if (scheduler_on_impl_thread_)
+ if (scheduler_on_impl_thread_) {
// Drawing implies we submitted a frame to the LayerTreeFrameSink.
- scheduler_on_impl_thread_->DidSubmitCompositorFrame();
+ scheduler_on_impl_thread_->DidSubmitCompositorFrame(
+ frame->frame_token);
+ }
single_thread_client_->DidSubmitCompositorFrame();
}
}
@@ -744,7 +755,7 @@ void SingleThreadProxy::ScheduledActionSendBeginMainFrame(
task_runner_provider_->MainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&SingleThreadProxy::BeginMainFrame,
weak_factory_.GetWeakPtr(), begin_frame_args));
- host_impl_->DidSendBeginMainFrame();
+ host_impl_->DidSendBeginMainFrame(begin_frame_args);
}
void SingleThreadProxy::FrameIntervalUpdated(base::TimeDelta interval) {
@@ -823,8 +834,7 @@ void SingleThreadProxy::BeginMainFrame(
// know we will commit since QueueSwapPromise itself requests a commit.
ui::LatencyInfo new_latency_info(ui::SourceEventType::FRAME);
new_latency_info.AddLatencyNumberWithTimestamp(
- ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT, begin_frame_args.frame_time,
- 1);
+ ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT, begin_frame_args.frame_time);
layer_tree_host_->QueueSwapPromise(
std::make_unique<LatencyInfoSwapPromise>(new_latency_info));
@@ -863,7 +873,9 @@ void SingleThreadProxy::BeginMainFrameAbortedOnImplThread(
DCHECK(!host_impl_->pending_tree());
std::vector<std::unique_ptr<SwapPromise>> empty_swap_promises;
- host_impl_->BeginMainFrameAborted(reason, std::move(empty_swap_promises));
+ host_impl_->BeginMainFrameAborted(
+ reason, std::move(empty_swap_promises),
+ scheduler_on_impl_thread_->last_dispatched_begin_main_frame_args());
scheduler_on_impl_thread_->BeginMainFrameAborted(reason);
}
@@ -872,6 +884,8 @@ DrawResult SingleThreadProxy::ScheduledActionDrawIfPossible() {
LayerTreeHostImpl::FrameData frame;
frame.begin_frame_ack =
scheduler_on_impl_thread_->CurrentBeginFrameAckForActiveTree();
+ frame.origin_begin_main_frame_args =
+ scheduler_on_impl_thread_->last_activate_origin_frame_args();
return DoComposite(&frame);
}
diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h
index 97a449b3442..320688ea79b 100644
--- a/chromium/cc/trees/single_thread_proxy.h
+++ b/chromium/cc/trees/single_thread_proxy.h
@@ -41,7 +41,6 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
// Proxy implementation
bool IsStarted() const override;
- bool CommitToActiveTree() const override;
void SetLayerTreeFrameSink(
LayerTreeFrameSink* layer_tree_frame_sink) override;
void ReleaseLayerTreeFrameSink() override;
@@ -115,6 +114,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
void PostAnimationEventsToMainThreadOnImplThread(
std::unique_ptr<MutatorEvents> events) override;
bool IsInsideDraw() override;
+ bool IsBeginMainFrameExpected() override;
void RenewTreePriority() override {}
void PostDelayedAnimationTaskOnImplThread(base::OnceClosure task,
base::TimeDelta delay) override {}
@@ -134,6 +134,8 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
void NotifyAnimationWorkletStateChange(
AnimationWorkletMutationState state,
ElementListType element_list_type) override;
+ void NotifyPaintWorkletStateChange(
+ Scheduler::PaintWorkletState state) override;
void RequestNewLayerTreeFrameSink();
@@ -206,9 +208,9 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
// WeakPtrs generated by this factory will be invalidated when
// LayerTreeFrameSink is released.
- base::WeakPtrFactory<SingleThreadProxy> frame_sink_bound_weak_factory_;
+ base::WeakPtrFactory<SingleThreadProxy> frame_sink_bound_weak_factory_{this};
- base::WeakPtrFactory<SingleThreadProxy> weak_factory_;
+ base::WeakPtrFactory<SingleThreadProxy> weak_factory_{this};
};
// For use in the single-threaded case. In debug builds, it pretends that the
diff --git a/chromium/cc/trees/transform_node.h b/chromium/cc/trees/transform_node.h
index 5a19ccec9e0..4f123a6390f 100644
--- a/chromium/cc/trees/transform_node.h
+++ b/chromium/cc/trees/transform_node.h
@@ -6,7 +6,7 @@
#define CC_TREES_TRANSFORM_NODE_H_
#include "cc/cc_export.h"
-#include "cc/trees/element_id.h"
+#include "cc/paint/element_id.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
#include "ui/gfx/transform.h"
@@ -67,7 +67,8 @@ struct CC_EXPORT TransformNode {
// context.
int sorting_context_id;
- // TODO(vollick): will be moved when accelerated effects are implemented.
+ // True if |TransformTree::UpdateLocalTransform| needs to be called which
+ // will update |to_parent| and |source_to_parent| (if possible).
bool needs_local_transform_update : 1;
// Whether this node or any ancestor has a potentially running
diff --git a/chromium/cc/trees/tree_synchronizer.cc b/chromium/cc/trees/tree_synchronizer.cc
index 9e329f02eaa..393e45b1167 100644
--- a/chromium/cc/trees/tree_synchronizer.cc
+++ b/chromium/cc/trees/tree_synchronizer.cc
@@ -41,14 +41,14 @@ static bool LayerHasValidPropertyTreeIndices(LayerImpl* layer) {
}
static bool LayerWillPushProperties(LayerTreeHost* host, Layer* layer) {
- return base::ContainsKey(host->LayersThatShouldPushProperties(), layer);
+ return base::Contains(host->LayersThatShouldPushProperties(), layer);
}
static bool LayerWillPushProperties(LayerTreeImpl* tree, LayerImpl* layer) {
- return base::ContainsKey(tree->LayersThatShouldPushProperties(), layer) ||
+ return base::Contains(tree->LayersThatShouldPushProperties(), layer) ||
// TODO(crbug.com/303943): Stop always pushing PictureLayerImpl
// properties.
- base::ContainsValue(tree->picture_layers(), layer);
+ base::Contains(tree->picture_layers(), layer);
}
#endif
diff --git a/chromium/cc/trees/tree_synchronizer_unittest.cc b/chromium/cc/trees/tree_synchronizer_unittest.cc
index b7a3dc02eee..6d0d4e5688e 100644
--- a/chromium/cc/trees/tree_synchronizer_unittest.cc
+++ b/chromium/cc/trees/tree_synchronizer_unittest.cc
@@ -200,7 +200,7 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeFromEmpty) {
host_->pending_tree());
LayerImpl* root = host_->pending_tree()->root_layer_for_testing();
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
host_->pending_tree()->LayersThatShouldPushProperties(), root));
ExpectTreesAreIdentical(layer_tree_root.get(),
@@ -226,7 +226,7 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndPushPropertiesFromEmpty) {
// layers are created on pending tree and they all need to push properties to
// active tree.
LayerImpl* root = host_->pending_tree()->root_layer_for_testing();
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
host_->pending_tree()->LayersThatShouldPushProperties(), root));
ExpectTreesAreIdentical(layer_tree_root.get(),
@@ -242,20 +242,20 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndPushPropertiesFromEmpty) {
host_->active_tree());
TreeSynchronizer::PushLayerProperties(host_->pending_tree(),
host_->active_tree());
- EXPECT_FALSE(base::ContainsKey(
+ EXPECT_FALSE(base::Contains(
host_->pending_tree()->LayersThatShouldPushProperties(), root));
// Set the main thread root layer needs push properties.
layer_tree_root->SetNeedsPushProperties();
- EXPECT_TRUE(base::ContainsKey(host_->LayersThatShouldPushProperties(),
- layer_tree_root.get()));
+ EXPECT_TRUE(base::Contains(host_->LayersThatShouldPushProperties(),
+ layer_tree_root.get()));
// When sync from main thread, the needs push properties status is carried
// over to pending tree.
TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
host_->pending_tree());
TreeSynchronizer::PushLayerProperties(host_.get(), host_->pending_tree());
- EXPECT_TRUE(base::ContainsKey(
+ EXPECT_TRUE(base::Contains(
host_->pending_tree()->LayersThatShouldPushProperties(), root));
}
@@ -278,8 +278,8 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeReusingLayers) {
LayerImpl* layer_impl_tree_root =
host_->pending_tree()->root_layer_for_testing();
EXPECT_TRUE(
- base::ContainsKey(host_->pending_tree()->LayersThatShouldPushProperties(),
- layer_impl_tree_root));
+ base::Contains(host_->pending_tree()->LayersThatShouldPushProperties(),
+ layer_impl_tree_root));
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->pending_tree());
@@ -522,12 +522,12 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeThenDestroy) {
ASSERT_EQ(3u, layer_impl_destruction_list.size());
- EXPECT_TRUE(base::ContainsValue(layer_impl_destruction_list,
- old_tree_root_layer_id));
- EXPECT_TRUE(base::ContainsValue(layer_impl_destruction_list,
- old_tree_first_child_layer_id));
- EXPECT_TRUE(base::ContainsValue(layer_impl_destruction_list,
- old_tree_second_child_layer_id));
+ EXPECT_TRUE(
+ base::Contains(layer_impl_destruction_list, old_tree_root_layer_id));
+ EXPECT_TRUE(base::Contains(layer_impl_destruction_list,
+ old_tree_first_child_layer_id));
+ EXPECT_TRUE(base::Contains(layer_impl_destruction_list,
+ old_tree_second_child_layer_id));
}
// Constructs+syncs a tree with mask layer.
diff --git a/chromium/cc/trees/viewport_layers.h b/chromium/cc/trees/viewport_layers.h
index 7cdb88bd27e..b92d1190bc1 100644
--- a/chromium/cc/trees/viewport_layers.h
+++ b/chromium/cc/trees/viewport_layers.h
@@ -6,7 +6,8 @@
#define CC_TREES_VIEWPORT_LAYERS_H_
#include "base/memory/ref_counted.h"
-#include "cc/trees/element_id.h"
+#include "cc/cc_export.h"
+#include "cc/paint/element_id.h"
namespace cc {
class Layer;