summaryrefslogtreecommitdiffstats
path: root/chromium/cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-28 15:28:34 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-28 13:54:51 +0000
commit2a19c63448c84c1805fb1a585c3651318bb86ca7 (patch)
treeeb17888e8531aa6ee5e85721bd553b832a7e5156 /chromium/cc
parentb014812705fc80bff0a5c120dfcef88f349816dc (diff)
BASELINE: Update Chromium to 69.0.3497.70
Change-Id: I2b7b56e4e7a8b26656930def0d4575dc32b900a0 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn36
-rw-r--r--chromium/cc/DEPS7
-rw-r--r--chromium/cc/animation/DEPS1
-rw-r--r--chromium/cc/animation/animation.cc13
-rw-r--r--chromium/cc/animation/animation.h12
-rw-r--r--chromium/cc/animation/animation_host.cc114
-rw-r--r--chromium/cc/animation/animation_host.h17
-rw-r--r--chromium/cc/animation/animation_host_unittest.cc76
-rw-r--r--chromium/cc/animation/animation_unittest.cc154
-rw-r--r--chromium/cc/animation/element_animations_unittest.cc68
-rw-r--r--chromium/cc/animation/keyframe_effect.cc42
-rw-r--r--chromium/cc/animation/keyframe_effect.h9
-rw-r--r--chromium/cc/animation/keyframe_model.cc53
-rw-r--r--chromium/cc/animation/keyframe_model.h37
-rw-r--r--chromium/cc/animation/scroll_offset_animations_impl.cc18
-rw-r--r--chromium/cc/animation/scroll_timeline.cc50
-rw-r--r--chromium/cc/animation/scroll_timeline.h23
-rw-r--r--chromium/cc/animation/scroll_timeline_unittest.cc65
-rw-r--r--chromium/cc/animation/single_keyframe_effect_animation.cc17
-rw-r--r--chromium/cc/animation/single_keyframe_effect_animation.h5
-rw-r--r--chromium/cc/animation/worklet_animation.cc147
-rw-r--r--chromium/cc/animation/worklet_animation.h82
-rw-r--r--chromium/cc/animation/worklet_animation_unittest.cc226
-rw-r--r--chromium/cc/base/list_container.h10
-rw-r--r--chromium/cc/base/list_container_unittest.cc168
-rw-r--r--chromium/cc/benchmarks/micro_benchmark.cc2
-rw-r--r--chromium/cc/benchmarks/micro_benchmark.h4
-rw-r--r--chromium/cc/input/browser_controls_offset_manager.cc21
-rw-r--r--chromium/cc/input/browser_controls_offset_manager_client.h2
-rw-r--r--chromium/cc/input/browser_controls_offset_manager_unittest.cc11
-rw-r--r--chromium/cc/input/browser_controls_state.h7
-rw-r--r--chromium/cc/input/event_listener_properties.h4
-rw-r--r--chromium/cc/input/input_handler.h14
-rw-r--r--chromium/cc/input/scroll_elasticity_helper.cc13
-rw-r--r--chromium/cc/input/scroll_snap_data.cc292
-rw-r--r--chromium/cc/input/scroll_snap_data.h123
-rw-r--r--chromium/cc/input/scroll_snap_data_unittest.cc204
-rw-r--r--chromium/cc/input/snap_fling_controller.h4
-rw-r--r--chromium/cc/input/snap_fling_curve.cc27
-rw-r--r--chromium/cc/input/snap_fling_curve.h4
-rw-r--r--chromium/cc/input/snap_fling_curve_unittest.cc22
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc18
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.h9
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl_unittest.cc10
-rw-r--r--chromium/cc/layers/heads_up_display_unittest.cc30
-rw-r--r--chromium/cc/layers/layer.cc164
-rw-r--r--chromium/cc/layers/layer.h666
-rw-r--r--chromium/cc/layers/layer_impl.cc64
-rw-r--r--chromium/cc/layers/layer_impl.h55
-rw-r--r--chromium/cc/layers/layer_impl_unittest.cc8
-rw-r--r--chromium/cc/layers/layer_list_iterator.cc2
-rw-r--r--chromium/cc/layers/layer_list_iterator_unittest.cc8
-rw-r--r--chromium/cc/layers/layer_position_constraint_unittest.cc37
-rw-r--r--chromium/cc/layers/layer_unittest.cc184
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl_unittest.cc8
-rw-r--r--chromium/cc/layers/nine_patch_layer_unittest.cc2
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer.cc4
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer.h1
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc2
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h2
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc3
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.cc4
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.h1
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.cc2
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.h2
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_unittest.cc3
-rw-r--r--chromium/cc/layers/picture_layer.h6
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc13
-rw-r--r--chromium/cc/layers/picture_layer_impl_perftest.cc2
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc7
-rw-r--r--chromium/cc/layers/picture_layer_unittest.cc8
-rw-r--r--chromium/cc/layers/render_surface_impl.cc5
-rw-r--r--chromium/cc/layers/render_surface_unittest.cc10
-rw-r--r--chromium/cc/layers/scrollbar_layer_unittest.cc28
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer.cc4
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer.h1
-rw-r--r--chromium/cc/layers/surface_layer.cc89
-rw-r--r--chromium/cc/layers/surface_layer.h15
-rw-r--r--chromium/cc/layers/surface_layer_impl.cc56
-rw-r--r--chromium/cc/layers/surface_layer_impl.h22
-rw-r--r--chromium/cc/layers/surface_layer_impl_unittest.cc3
-rw-r--r--chromium/cc/layers/surface_layer_unittest.cc107
-rw-r--r--chromium/cc/layers/texture_layer.cc7
-rw-r--r--chromium/cc/layers/texture_layer.h2
-rw-r--r--chromium/cc/layers/texture_layer_impl.cc33
-rw-r--r--chromium/cc/layers/texture_layer_impl.h9
-rw-r--r--chromium/cc/layers/texture_layer_impl_unittest.cc10
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc251
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl.cc2
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl.h7
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl_unittest.cc12
-rw-r--r--chromium/cc/layers/ui_resource_layer_unittest.cc4
-rw-r--r--chromium/cc/layers/video_frame_provider.h11
-rw-r--r--chromium/cc/layers/video_frame_provider_client_impl.cc5
-rw-r--r--chromium/cc/layers/video_frame_provider_client_impl.h1
-rw-r--r--chromium/cc/layers/video_layer_impl.cc15
-rw-r--r--chromium/cc/layers/video_layer_impl.h8
-rw-r--r--chromium/cc/layers/video_layer_impl_unittest.cc5
-rw-r--r--chromium/cc/layers/viewport.cc104
-rw-r--r--chromium/cc/layers/viewport.h6
-rw-r--r--chromium/cc/mojo_embedder/BUILD.gn24
-rw-r--r--chromium/cc/mojo_embedder/DEPS4
-rw-r--r--chromium/cc/mojo_embedder/README.md4
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc256
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h149
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc118
-rw-r--r--chromium/cc/mojo_embedder/mojo_embedder_export.h29
-rw-r--r--chromium/cc/paint/decoded_draw_image.cc2
-rw-r--r--chromium/cc/paint/decoded_draw_image.h5
-rw-r--r--chromium/cc/paint/display_item_list.cc3
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.cc109
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.h16
-rw-r--r--chromium/cc/paint/oop_pixeltest.cc229
-rw-r--r--chromium/cc/paint/paint_canvas.h7
-rw-r--r--chromium/cc/paint/paint_filter.h8
-rw-r--r--chromium/cc/paint/paint_image.cc22
-rw-r--r--chromium/cc/paint/paint_image.h10
-rw-r--r--chromium/cc/paint/paint_image_unittest.cc23
-rw-r--r--chromium/cc/paint/paint_op_buffer.cc20
-rw-r--r--chromium/cc/paint/paint_op_buffer.h15
-rw-r--r--chromium/cc/paint/paint_op_buffer_fuzzer.cc84
-rw-r--r--chromium/cc/paint/paint_op_buffer_serializer.cc188
-rw-r--r--chromium/cc/paint/paint_op_buffer_serializer.h17
-rw-r--r--chromium/cc/paint/paint_op_buffer_unittest.cc139
-rw-r--r--chromium/cc/paint/paint_op_perftest.cc5
-rw-r--r--chromium/cc/paint/paint_op_reader.cc28
-rw-r--r--chromium/cc/paint/paint_op_reader.h1
-rw-r--r--chromium/cc/paint/paint_op_writer.cc37
-rw-r--r--chromium/cc/paint/paint_op_writer.h7
-rw-r--r--chromium/cc/paint/paint_shader.cc35
-rw-r--r--chromium/cc/paint/paint_shader.h4
-rw-r--r--chromium/cc/paint/paint_typeface.cc2
-rw-r--r--chromium/cc/paint/record_paint_canvas.cc17
-rw-r--r--chromium/cc/paint/record_paint_canvas.h5
-rw-r--r--chromium/cc/paint/scoped_raster_flags.cc5
-rw-r--r--chromium/cc/paint/skia_paint_canvas.cc17
-rw-r--r--chromium/cc/paint/skia_paint_canvas.h5
-rw-r--r--chromium/cc/paint/solid_color_analyzer_unittest.cc8
-rw-r--r--chromium/cc/paint/transfer_cache_unittest.cc29
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.cc17
-rw-r--r--chromium/cc/raster/one_copy_raster_buffer_provider.cc5
-rw-r--r--chromium/cc/raster/one_copy_raster_buffer_provider.h2
-rw-r--r--chromium/cc/raster/playback_image_provider.cc13
-rw-r--r--chromium/cc/raster/playback_image_provider_unittest.cc25
-rw-r--r--chromium/cc/raster/raster_buffer_provider.cc18
-rw-r--r--chromium/cc/raster/raster_buffer_provider_perftest.cc14
-rw-r--r--chromium/cc/raster/raster_buffer_provider_unittest.cc21
-rw-r--r--chromium/cc/raster/raster_source.cc65
-rw-r--r--chromium/cc/raster/raster_source.h9
-rw-r--r--chromium/cc/raster/staging_buffer_pool.cc18
-rw-r--r--chromium/cc/raster/staging_buffer_pool.h8
-rw-r--r--chromium/cc/raster/zero_copy_raster_buffer_provider.cc14
-rw-r--r--chromium/cc/resources/cross_thread_shared_bitmap.h2
-rw-r--r--chromium/cc/resources/layer_tree_resource_provider.cc307
-rw-r--r--chromium/cc/resources/layer_tree_resource_provider.h127
-rw-r--r--chromium/cc/resources/layer_tree_resource_provider_unittest.cc556
-rw-r--r--chromium/cc/resources/resource_pool.cc26
-rw-r--r--chromium/cc/resources/resource_pool.h18
-rw-r--r--chromium/cc/resources/resource_pool_unittest.cc13
-rw-r--r--chromium/cc/resources/shared_bitmap_id_registrar.h2
-rw-r--r--chromium/cc/resources/video_resource_updater.cc1155
-rw-r--r--chromium/cc/resources/video_resource_updater.h220
-rw-r--r--chromium/cc/resources/video_resource_updater_unittest.cc737
-rw-r--r--chromium/cc/scheduler/compositor_timing_history.cc73
-rw-r--r--chromium/cc/scheduler/compositor_timing_history.h4
-rw-r--r--chromium/cc/scheduler/compositor_timing_history_unittest.cc2
-rw-r--r--chromium/cc/scheduler/draw_result.h4
-rw-r--r--chromium/cc/scheduler/scheduler.cc17
-rw-r--r--chromium/cc/scheduler/scheduler.h8
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.cc8
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.h8
-rw-r--r--chromium/cc/scheduler/scheduler_unittest.cc614
-rw-r--r--chromium/cc/tiles/frame_viewer_instrumentation.cc5
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.cc556
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.h65
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_perftest.cc183
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_unittest.cc397
-rw-r--r--chromium/cc/tiles/image_decode_cache.h5
-rw-r--r--chromium/cc/tiles/mipmap_util.cc16
-rw-r--r--chromium/cc/tiles/mipmap_util_unittest.cc14
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set_unittest.cc8
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.cc206
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.h10
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_unittest.cc161
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_utils.cc1
-rw-r--r--chromium/cc/tiles/tile_manager_perftest.cc4
-rw-r--r--chromium/cc/trees/animation_options.h25
-rw-r--r--chromium/cc/trees/draw_property_utils.cc84
-rw-r--r--chromium/cc/trees/draw_property_utils.h9
-rw-r--r--chromium/cc/trees/element_id.cc2
-rw-r--r--chromium/cc/trees/element_id.h4
-rw-r--r--chromium/cc/trees/frame_rate_counter.cc12
-rw-r--r--chromium/cc/trees/frame_token_allocator.cc26
-rw-r--r--chromium/cc/trees/frame_token_allocator.h52
-rw-r--r--chromium/cc/trees/latency_info_swap_promise.cc27
-rw-r--r--chromium/cc/trees/latency_info_swap_promise.h5
-rw-r--r--chromium/cc/trees/latency_info_swap_promise_monitor.cc10
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink.h25
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink_client.h13
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink_unittest.cc6
-rw-r--r--chromium/cc/trees/layer_tree_host.cc242
-rw-r--r--chromium/cc/trees/layer_tree_host.h62
-rw-r--r--chromium/cc/trees/layer_tree_host_client.h8
-rw-r--r--chromium/cc/trees/layer_tree_host_common.cc59
-rw-r--r--chromium/cc/trees/layer_tree_host_common.h11
-rw-r--r--chromium/cc/trees/layer_tree_host_common_perftest.cc6
-rw-r--r--chromium/cc/trees/layer_tree_host_common_unittest.cc114
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc665
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h183
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc1375
-rw-r--r--chromium/cc/trees/layer_tree_host_perftest.cc2
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc11
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc363
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_animation.cc108
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_context.cc182
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc14
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_occlusion.cc4
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_scroll.cc138
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc376
-rw-r--r--chromium/cc/trees/layer_tree_impl.h81
-rw-r--r--chromium/cc/trees/layer_tree_impl_unittest.cc93
-rw-r--r--chromium/cc/trees/layer_tree_mutator.cc80
-rw-r--r--chromium/cc/trees/layer_tree_mutator.h94
-rw-r--r--chromium/cc/trees/layer_tree_settings.h8
-rw-r--r--chromium/cc/trees/mutator_host.h4
-rw-r--r--chromium/cc/trees/property_tree.cc36
-rw-r--r--chromium/cc/trees/property_tree.h2
-rw-r--r--chromium/cc/trees/property_tree_builder.cc173
-rw-r--r--chromium/cc/trees/property_tree_unittest.cc134
-rw-r--r--chromium/cc/trees/proxy.h8
-rw-r--r--chromium/cc/trees/proxy_impl.cc33
-rw-r--r--chromium/cc/trees/proxy_impl.h15
-rw-r--r--chromium/cc/trees/proxy_main.cc29
-rw-r--r--chromium/cc/trees/proxy_main.h12
-rw-r--r--chromium/cc/trees/render_frame_metadata.cc32
-rw-r--r--chromium/cc/trees/render_frame_metadata.h25
-rw-r--r--chromium/cc/trees/render_frame_metadata_observer.h13
-rw-r--r--chromium/cc/trees/single_thread_proxy.cc38
-rw-r--r--chromium/cc/trees/single_thread_proxy.h16
-rw-r--r--chromium/cc/trees/swap_promise.h20
-rw-r--r--chromium/cc/trees/swap_promise_manager_unittest.cc7
-rw-r--r--chromium/cc/trees/tree_synchronizer_unittest.cc11
242 files changed, 8968 insertions, 8027 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
index 4f6b936f03f..a70ef19a273 100644
--- a/chromium/cc/BUILD.gn
+++ b/chromium/cc/BUILD.gn
@@ -180,8 +180,6 @@ cc_component("cc") {
"raster/zero_copy_raster_buffer_provider.h",
"resources/cross_thread_shared_bitmap.cc",
"resources/cross_thread_shared_bitmap.h",
- "resources/layer_tree_resource_provider.cc",
- "resources/layer_tree_resource_provider.h",
"resources/memory_history.cc",
"resources/memory_history.h",
"resources/resource_pool.cc",
@@ -197,8 +195,6 @@ cc_component("cc") {
"resources/ui_resource_manager.h",
"resources/ui_resource_request.cc",
"resources/ui_resource_request.h",
- "resources/video_resource_updater.cc",
- "resources/video_resource_updater.h",
"scheduler/begin_frame_tracker.cc",
"scheduler/begin_frame_tracker.h",
"scheduler/commit_earlyout_reason.h",
@@ -261,6 +257,7 @@ cc_component("cc") {
"tiles/tiling_set_raster_queue_all.h",
"tiles/tiling_set_raster_queue_required.cc",
"tiles/tiling_set_raster_queue_required.h",
+ "trees/animation_options.h",
"trees/clip_expander.cc",
"trees/clip_expander.h",
"trees/clip_node.cc",
@@ -278,8 +275,6 @@ cc_component("cc") {
"trees/element_id.h",
"trees/frame_rate_counter.cc",
"trees/frame_rate_counter.h",
- "trees/frame_token_allocator.cc",
- "trees/frame_token_allocator.h",
"trees/image_animation_controller.cc",
"trees/image_animation_controller.h",
"trees/latency_info_swap_promise.cc",
@@ -369,17 +364,16 @@ cc_component("cc") {
"//base",
"//base/third_party/dynamic_annotations",
"//components/ukm",
- "//components/viz/common",
+ "//components/viz/client",
"//gpu",
"//gpu/command_buffer/client:gles2_interface",
"//gpu/command_buffer/client:raster_interface",
"//gpu/ipc:gl_in_process_context",
"//gpu/skia_bindings:skia_bindings",
"//gpu/vulkan:buildflags",
- "//media",
+ "//media", # For VideoLayerImpl.
"//mojo/public/cpp/bindings:struct_traits",
"//services/metrics/public/cpp:ukm_builders",
- "//third_party/libyuv",
"//ui/events:events_base",
"//ui/gfx",
"//ui/gfx/geometry",
@@ -435,7 +429,6 @@ cc_static_library("test_support") {
"test/fake_recording_source.cc",
"test/fake_recording_source.h",
"test/fake_rendering_stats_instrumentation.h",
- "test/fake_resource_provider.h",
"test/fake_scoped_ui_resource.cc",
"test/fake_scoped_ui_resource.h",
"test/fake_scrollbar.cc",
@@ -536,6 +529,7 @@ cc_static_library("test_support") {
"//cc/paint",
"//components/ukm",
"//components/ukm:test_support",
+ "//components/viz/client",
"//components/viz/common",
"//components/viz/service",
"//components/viz/test:test_support",
@@ -543,8 +537,10 @@ cc_static_library("test_support") {
"//gpu/command_buffer/client:raster",
"//gpu/command_buffer/common",
"//gpu/ipc:gl_in_process_context",
+ "//gpu/ipc/service",
"//gpu/skia_bindings",
"//media",
+ "//services/viz/privileged/interfaces",
"//skia",
"//testing/gtest",
"//ui/gfx",
@@ -618,6 +614,7 @@ cc_test("cc_unittests") {
"layers/video_frame_provider_client_impl_unittest.cc",
"layers/video_layer_impl_unittest.cc",
"layers/viewport_unittest.cc",
+ "mojo_embedder/async_layer_tree_frame_sink_unittest.cc",
"paint/discardable_image_map_unittest.cc",
"paint/display_item_list_unittest.cc",
"paint/filter_operations_unittest.cc",
@@ -640,9 +637,7 @@ cc_test("cc_unittests") {
"raster/synchronous_task_graph_runner_unittest.cc",
"raster/task_graph_work_queue_unittest.cc",
"raster/texture_compressor_etc1_unittest.cc",
- "resources/layer_tree_resource_provider_unittest.cc",
"resources/resource_pool_unittest.cc",
- "resources/video_resource_updater_unittest.cc",
"scheduler/compositor_timing_history_unittest.cc",
"scheduler/scheduler_state_machine_unittest.cc",
"scheduler/scheduler_unittest.cc",
@@ -729,8 +724,10 @@ cc_test("cc_unittests") {
":cc",
":test_support",
"//base/test:test_support",
+ "//cc/mojo_embedder",
"//cc/paint",
"//components/ukm:test_support",
+ "//components/viz/client",
"//components/viz/common",
"//components/viz/service",
"//components/viz/test:test_support",
@@ -743,7 +740,7 @@ cc_test("cc_unittests") {
"//gpu/ipc:gl_in_process_context",
"//gpu/skia_bindings",
"//media",
- "//mojo/edk",
+ "//mojo/core/embedder",
"//mojo/public/cpp/bindings",
"//testing/gmock",
"//testing/gtest",
@@ -773,6 +770,7 @@ cc_test("cc_perftests") {
"test/cc_test_suite.cc",
"test/cc_test_suite.h",
"test/run_all_perftests.cc",
+ "tiles/gpu_image_decode_cache_perftest.cc",
"tiles/software_image_decode_cache_perftest.cc",
"tiles/tile_manager_perftest.cc",
"trees/layer_tree_host_common_perftest.cc",
@@ -785,15 +783,18 @@ cc_test("cc_perftests") {
"//base",
"//base/test:test_support",
"//cc/paint",
+ "//components/viz/client",
"//components/viz/common",
"//components/viz/test:test_support",
"//gpu",
"//gpu:test_support",
"//gpu/command_buffer/client:gles2_implementation",
"//gpu/command_buffer/client:raster",
+ "//gpu/command_buffer/client:raster_interface",
+ "//gpu/ipc:gl_in_process_context",
"//gpu/ipc/common:struct_traits",
"//media",
- "//mojo/edk",
+ "//mojo/core/embedder",
"//mojo/public/cpp/bindings",
"//services/viz/public/interfaces",
"//skia",
@@ -811,11 +812,10 @@ cc_test("cc_perftests") {
data = [
"//components/viz/test/data/",
+ ]
+ data_deps = [
# Needed for isolate script to execute.
- "//testing/scripts/common.py",
- "//testing/xvfb.py",
- "//testing/scripts/run_gtest_perf_test.py",
- "//tools/perf/generate_legacy_perf_dashboard_json.py",
+ "//testing:run_perf_test",
]
}
diff --git a/chromium/cc/DEPS b/chromium/cc/DEPS
index 2e684073776..7b0e07a0097 100644
--- a/chromium/cc/DEPS
+++ b/chromium/cc/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+components/ukm/test_ukm_recorder.h",
+ "+components/viz/client",
"+components/viz/common",
"+gpu/GLES2",
"+gpu/command_buffer/client/context_support.h",
@@ -28,9 +29,13 @@ include_rules = [
"+third_party/libyuv",
"+third_party/skia/include",
"+third_party/skia/src/core/SkRemoteGlyphCache.h",
- "+ui/latency/latency_info.h",
+ "+ui/latency",
"+ui/gfx",
"+ui/gl",
+
+ # Do not use mojo bindings in cc/. This library should be agnostic about how
+ # to communicate with viz.
+ "-mojo/public/cpp/bindings",
]
specific_include_rules = {
diff --git a/chromium/cc/animation/DEPS b/chromium/cc/animation/DEPS
index a59045da943..6afc308b2a6 100644
--- a/chromium/cc/animation/DEPS
+++ b/chromium/cc/animation/DEPS
@@ -6,6 +6,7 @@ include_rules = [
"+cc/paint",
"+cc/output/filter_operations.h",
"+cc/test",
+ "+cc/trees/animation_options.h",
"+cc/trees/element_id.h",
"+cc/trees/mutator_host.h",
"+cc/trees/mutator_host_client.h",
diff --git a/chromium/cc/animation/animation.cc b/chromium/cc/animation/animation.cc
index 57af2598821..8da03807dcf 100644
--- a/chromium/cc/animation/animation.cc
+++ b/chromium/cc/animation/animation.cc
@@ -13,6 +13,7 @@
#include "cc/animation/animation_events.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_timeline.h"
+#include "cc/animation/keyframe_effect.h"
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/transform_operations.h"
#include "cc/trees/property_animation_state.h"
@@ -229,13 +230,19 @@ void Animation::AbortKeyframeModelForKeyframeEffect(
->AbortKeyframeModel(keyframe_model_id);
}
-void Animation::AbortKeyframeModels(TargetProperty::Type target_property,
- bool needs_completion) {
+void Animation::AbortKeyframeModelsWithProperty(
+ TargetProperty::Type target_property,
+ bool needs_completion) {
for (auto& keyframe_effect : keyframe_effects_)
- keyframe_effect->AbortKeyframeModels(target_property, needs_completion);
+ keyframe_effect->AbortKeyframeModelsWithProperty(target_property,
+ needs_completion);
}
void Animation::PushPropertiesTo(Animation* animation_impl) {
+ // In general when pushing proerties to impl thread we first push attached
+ // properties to impl followed by removing the detached ones. However, we
+ // never remove individual keyframe effect from an animation so there is no
+ // need to remove the detached ones.
PushAttachedKeyframeEffectsToImplThread(animation_impl);
PushPropertiesToImplThread(animation_impl);
}
diff --git a/chromium/cc/animation/animation.h b/chromium/cc/animation/animation.h
index 6ac050dfabe..fe0a875ffe9 100644
--- a/chromium/cc/animation/animation.h
+++ b/chromium/cc/animation/animation.h
@@ -14,7 +14,6 @@
#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/element_animations.h"
-#include "cc/animation/keyframe_effect.h"
#include "cc/animation/keyframe_model.h"
#include "cc/trees/element_id.h"
@@ -24,6 +23,7 @@ class AnimationDelegate;
class AnimationEvents;
class AnimationHost;
class AnimationTimeline;
+class KeyframeEffect;
struct AnimationEvent;
// An Animation is responsible for managing animating properties for a set of
@@ -62,6 +62,10 @@ class CC_ANIMATION_EXPORT Animation : public base::RefCounted<Animation> {
}
virtual void SetAnimationTimeline(AnimationTimeline* timeline);
+ // TODO(smcgruer): If/once ScrollTimeline is supported on normal Animations,
+ // we will need to move the promotion logic from WorkletAnimation to here.
+ virtual void PromoteScrollTimelinePendingToActive() {}
+
bool has_element_animations() const;
scoped_refptr<ElementAnimations> element_animations(
KeyframeEffectId keyframe_effect_id) const;
@@ -87,10 +91,10 @@ class CC_ANIMATION_EXPORT Animation : public base::RefCounted<Animation> {
KeyframeEffectId keyframe_effect_id);
void AbortKeyframeModelForKeyframeEffect(int keyframe_model_id,
KeyframeEffectId keyframe_effect_id);
- void AbortKeyframeModels(TargetProperty::Type target_property,
- bool needs_completion);
+ void AbortKeyframeModelsWithProperty(TargetProperty::Type target_property,
+ bool needs_completion);
- void PushPropertiesTo(Animation* animation_impl);
+ virtual void PushPropertiesTo(Animation* animation_impl);
void UpdateState(bool start_ready_keyframe_models, AnimationEvents* events);
virtual void Tick(base::TimeTicks monotonic_time);
diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc
index cc1f51ad0f3..e3a4a2a25ce 100644
--- a/chromium/cc/animation/animation_host.cc
+++ b/chromium/cc/animation/animation_host.cc
@@ -30,13 +30,6 @@
namespace cc {
-namespace {
-WorkletAnimation* ToWorkletAnimation(Animation* animation) {
- DCHECK(animation->IsWorkletAnimation());
- return static_cast<WorkletAnimation*>(animation);
-}
-} // namespace
-
std::unique_ptr<AnimationHost> AnimationHost::CreateMainInstance() {
return base::WrapUnique(new AnimationHost(ThreadInstance::MAIN));
}
@@ -282,21 +275,20 @@ bool AnimationHost::NeedsTickAnimations() const {
return !ticking_animations_.empty();
}
-bool AnimationHost::NeedsTickMutator(base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree) const {
+bool AnimationHost::TickMutator(base::TimeTicks monotonic_time,
+ const ScrollTree& scroll_tree,
+ bool is_active_tree) {
if (!mutator_ || !mutator_->HasAnimators())
return false;
- for (auto& animation : ticking_animations_) {
- if (!animation->IsWorkletAnimation())
- continue;
+ std::unique_ptr<MutatorInputState> state = CollectWorkletAnimationsState(
+ monotonic_time, scroll_tree, is_active_tree);
+ if (state->IsEmpty())
+ return false;
- if (ToWorkletAnimation(animation.get())
- ->NeedsUpdate(monotonic_time, scroll_tree))
- return true;
- }
+ mutator_->Mutate(std::move(state));
- return false;
+ return true;
}
bool AnimationHost::ActivateAnimations() {
@@ -312,50 +304,47 @@ bool AnimationHost::ActivateAnimations() {
}
bool AnimationHost::TickAnimations(base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree) {
+ const ScrollTree& scroll_tree,
+ bool is_active_tree) {
TRACE_EVENT0("cc", "AnimationHost::TickAnimations");
- bool did_animate = false;
+ // Notes on ordering between a) ticking mutator b) ticking animations: Since
+ // (a) is currently synchronous by doing a, b in that order we ensure worklet
+ // animation output state is up-to-date before having that output actually
+ // take effect in (b). This gaurantees worklet animation output takes effect
+ // in the same impl frame that it was mutated.
+ // TODO(crbug.com/834452): We will need a different approach when we make (a)
+ // asynchronous but until then this simple ordering is sufficient.
- if (NeedsTickAnimations()) {
- TRACE_EVENT_INSTANT0("cc", "NeedsTickAnimations", TRACE_EVENT_SCOPE_THREAD);
- AnimationsList ticking_animations_copy = ticking_animations_;
- for (auto& it : ticking_animations_copy)
- it->Tick(monotonic_time);
+ if (!NeedsTickAnimations())
+ return false;
- did_animate = true;
- }
- if (NeedsTickMutator(monotonic_time, scroll_tree)) {
- // TODO(majidvp): At the moment we call this for both active and pending
- // trees similar to other animations. However our final goal is to only call
- // it once, ideally after activation, and only when the input
- // to an active timeline has changed. http://crbug.com/767210
- mutator_->Mutate(CollectAnimatorsState(monotonic_time, scroll_tree));
- did_animate = true;
- }
+ TRACE_EVENT_INSTANT0("cc", "NeedsTickAnimations", TRACE_EVENT_SCOPE_THREAD);
- return did_animate;
+ // TODO(majidvp): At the moment we call this for both active and pending
+ // trees similar to other animations. However our final goal is to only call
+ // it once, ideally after activation, and only when the input
+ // to an active timeline has changed. http://crbug.com/767210
+ TickMutator(monotonic_time, scroll_tree, is_active_tree);
+
+ AnimationsList ticking_animations_copy = ticking_animations_;
+ for (auto& it : ticking_animations_copy)
+ it->Tick(monotonic_time);
+
+ return true;
}
void AnimationHost::TickScrollAnimations(base::TimeTicks monotonic_time,
const ScrollTree& scroll_tree) {
- // TODO(majidvp) For now the logic simply generates an update when at least
- // one animation needs updating but this is inefficient. We need a more
- // fine-grained approach based on invalidating individual ScrollTimelines and
- // then ticking the animations attached to those timelines. To make
- // this happen we probably need to move "ticking" animations to timeline.
- if (!NeedsTickMutator(monotonic_time, scroll_tree))
- return;
- DCHECK(mutator_);
-
// TODO(majidvp): We need to return a boolean here so that LTHI knows
// whether it needs to schedule another frame.
- mutator_->Mutate(CollectAnimatorsState(monotonic_time, scroll_tree));
+ TickMutator(monotonic_time, scroll_tree, true /* is_active_tree */);
}
-std::unique_ptr<MutatorInputState> AnimationHost::CollectAnimatorsState(
+std::unique_ptr<MutatorInputState> AnimationHost::CollectWorkletAnimationsState(
base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree) {
- TRACE_EVENT0("cc", "AnimationHost::CollectAnimatorsState");
+ const ScrollTree& scroll_tree,
+ bool is_active_tree) {
+ TRACE_EVENT0("cc", "AnimationHost::CollectWorkletAnimationsState");
std::unique_ptr<MutatorInputState> result =
std::make_unique<MutatorInputState>();
@@ -363,12 +352,9 @@ std::unique_ptr<MutatorInputState> AnimationHost::CollectAnimatorsState(
if (!animation->IsWorkletAnimation())
continue;
- WorkletAnimation* worklet_animation = ToWorkletAnimation(animation.get());
- MutatorInputState::AnimationState state{
- worklet_animation->id(), worklet_animation->name(),
- worklet_animation->CurrentTime(monotonic_time, scroll_tree)};
-
- result->animations.push_back(std::move(state));
+ ToWorkletAnimation(animation.get())
+ ->UpdateInputState(result.get(), monotonic_time, scroll_tree,
+ is_active_tree);
}
return result;
@@ -389,6 +375,12 @@ bool AnimationHost::UpdateAnimationState(bool start_ready_animations,
return true;
}
+void AnimationHost::PromoteScrollTimelinesPendingToActive() {
+ for (auto& animation : ticking_animations_) {
+ animation->PromoteScrollTimelinePendingToActive();
+ }
+}
+
std::unique_ptr<MutatorEvents> AnimationHost::CreateEvents() {
return std::make_unique<AnimationEvents>();
}
@@ -628,19 +620,19 @@ void AnimationHost::SetMutationUpdate(
TRACE_EVENT0("cc", "AnimationHost::SetMutationUpdate");
for (auto& animation_state : output_state->animations) {
- int id = animation_state.animation_id;
+ WorkletAnimationId id = animation_state.worklet_animation_id;
// TODO(majidvp): Use a map to make lookup O(1)
- auto to_update =
- std::find_if(ticking_animations_.begin(), ticking_animations_.end(),
- [id](auto& it) { return it->id() == id; });
+ auto to_update = std::find_if(
+ ticking_animations_.begin(), ticking_animations_.end(), [id](auto& it) {
+ return it->IsWorkletAnimation() &&
+ ToWorkletAnimation(it.get())->worklet_animation_id() == id;
+ });
if (to_update == ticking_animations_.end())
continue;
- DCHECK(to_update->get()->IsWorkletAnimation());
- ToWorkletAnimation(to_update->get())
- ->SetLocalTime(animation_state.local_time);
+ ToWorkletAnimation(to_update->get())->SetOutputState(animation_state);
}
}
diff --git a/chromium/cc/animation/animation_host.h b/chromium/cc/animation/animation_host.h
index beae9903713..fd582c4ee4b 100644
--- a/chromium/cc/animation/animation_host.h
+++ b/chromium/cc/animation/animation_host.h
@@ -102,11 +102,13 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost,
bool ActivateAnimations() override;
bool TickAnimations(base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree) override;
+ const ScrollTree& scroll_tree,
+ bool is_active_tree) override;
void TickScrollAnimations(base::TimeTicks monotonic_time,
const ScrollTree& scroll_tree) override;
bool UpdateAnimationState(bool start_ready_animations,
MutatorEvents* events) override;
+ void PromoteScrollTimelinesPendingToActive() override;
std::unique_ptr<MutatorEvents> CreateEvents() override;
void SetAnimationEvents(std::unique_ptr<MutatorEvents> events) override;
@@ -198,13 +200,16 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost,
void EraseTimeline(scoped_refptr<AnimationTimeline> timeline);
- bool NeedsTickMutator(base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree) const;
+ // Return true if there are any animations that get mutated.
+ bool TickMutator(base::TimeTicks monotonic_time,
+ const ScrollTree& scroll_tree,
+ bool is_active_tree);
- // Return the animator state representing all ticking worklet animations.
- std::unique_ptr<MutatorInputState> CollectAnimatorsState(
+ // Return the state representing all ticking worklet animations.
+ std::unique_ptr<MutatorInputState> CollectWorkletAnimationsState(
base::TimeTicks timeline_time,
- const ScrollTree& scroll_tree);
+ const ScrollTree& scroll_tree,
+ bool is_active_tree);
ElementToAnimationsMap element_to_animations_map_;
AnimationsList ticking_animations_;
diff --git a/chromium/cc/animation/animation_host_unittest.cc b/chromium/cc/animation/animation_host_unittest.cc
index df816b46085..e78e5d8e289 100644
--- a/chromium/cc/animation/animation_host_unittest.cc
+++ b/chromium/cc/animation/animation_host_unittest.cc
@@ -4,13 +4,23 @@
#include "cc/animation/animation_host.h"
+#include "base/memory/ptr_util.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_timeline.h"
+#include "cc/animation/scroll_timeline.h"
+#include "cc/animation/worklet_animation.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/animation_timelines_test_common.h"
+#include "cc/test/mock_layer_tree_mutator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using ::testing::InvokeWithoutArgs;
+using ::testing::Mock;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::_;
+
namespace cc {
namespace {
@@ -18,6 +28,33 @@ class AnimationHostTest : public AnimationTimelinesTest {
public:
AnimationHostTest() = default;
~AnimationHostTest() override = default;
+
+ void AttachWorkletAnimation() {
+ client_.RegisterElement(element_id_, ElementListType::ACTIVE);
+ client_impl_.RegisterElement(element_id_, ElementListType::PENDING);
+ client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE);
+
+ worklet_animation_ = WorkletAnimation::Create(
+ worklet_animation_id_, "test_name", nullptr, nullptr);
+ int cc_id = worklet_animation_->id();
+ worklet_animation_->AttachElement(element_id_);
+ host_->AddAnimationTimeline(timeline_);
+ timeline_->AttachAnimation(worklet_animation_);
+
+ host_->PushPropertiesTo(host_impl_);
+ timeline_impl_ = host_impl_->GetTimelineById(timeline_id_);
+ worklet_animation_impl_ =
+ ToWorkletAnimation(timeline_impl_->GetAnimationById(cc_id));
+ }
+
+ void SetOutputState(base::TimeDelta local_time) {
+ worklet_animation_impl_->SetOutputState(
+ {worklet_animation_id_, local_time});
+ }
+
+ scoped_refptr<WorkletAnimation> worklet_animation_;
+ scoped_refptr<WorkletAnimation> worklet_animation_impl_;
+ WorkletAnimationId worklet_animation_id_{11, 12};
};
// See Animation tests on layer registration/unregistration in
@@ -107,5 +144,44 @@ TEST_F(AnimationHostTest, ImplOnlyScrollAnimationUpdateTargetIfDetached) {
element_id_, scroll_delta, max_scroll_offset, time, base::TimeDelta()));
}
+// Tests that verify interaction of AnimationHost with LayerTreeMutator.
+
+TEST_F(AnimationHostTest, LayerTreeMutatorUpdateTakesEffectInSameFrame) {
+ AttachWorkletAnimation();
+
+ const float start_opacity = .7f;
+ const float end_opacity = .3f;
+ const double duration = 1.;
+
+ const float expected_opacity =
+ start_opacity + (end_opacity - start_opacity) / 2;
+ AddOpacityTransitionToAnimation(worklet_animation_.get(), duration,
+ start_opacity, end_opacity, true);
+
+ base::TimeDelta local_time = base::TimeDelta::FromSecondsD(duration / 2);
+
+ MockLayerTreeMutator* mock_mutator = new NiceMock<MockLayerTreeMutator>();
+ host_impl_->SetLayerTreeMutator(
+ base::WrapUnique<LayerTreeMutator>(mock_mutator));
+ ON_CALL(*mock_mutator, HasAnimators()).WillByDefault(Return(true));
+ ON_CALL(*mock_mutator, MutateRef(_))
+ .WillByDefault(InvokeWithoutArgs(
+ [this, local_time]() { this->SetOutputState(local_time); }));
+
+ // Push the opacity animation to the impl thread.
+ host_->PushPropertiesTo(host_impl_);
+ host_impl_->ActivateAnimations();
+
+ // Ticking host should cause layer tree mutator to update output state which
+ // should take effect in the same animation frame.
+ TickAnimationsTransferEvents(base::TimeTicks(), 0u);
+
+ TestLayer* layer =
+ client_.FindTestLayer(element_id_, ElementListType::ACTIVE);
+ EXPECT_FALSE(layer->is_property_mutated(TargetProperty::OPACITY));
+ client_impl_.ExpectOpacityPropertyMutated(
+ element_id_, ElementListType::ACTIVE, expected_opacity);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/animation/animation_unittest.cc b/chromium/cc/animation/animation_unittest.cc
index 6bef965ac93..cb09ab0ea21 100644
--- a/chromium/cc/animation/animation_unittest.cc
+++ b/chromium/cc/animation/animation_unittest.cc
@@ -21,123 +21,11 @@ namespace {
class AnimationTest : public AnimationTimelinesTest {
public:
- AnimationTest()
- : animation_(Animation::Create(animation_id_)),
- group_id_(100),
- keyframe_model_id_(100) {
+ AnimationTest() : animation_(Animation::Create(animation_id_)) {
keyframe_effect_id_ = animation_->NextKeyframeEffectId();
}
~AnimationTest() override = default;
- int NextGroupId() { return ++group_id_; }
-
- int NextKeyframeModelId() { return ++keyframe_model_id_; }
-
- int AddOpacityTransition(Animation* target,
- double duration,
- float start_opacity,
- float end_opacity,
- bool use_timing_function,
- KeyframeEffectId keyframe_effect_id) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
-
- std::unique_ptr<TimingFunction> func;
- if (!use_timing_function)
- func = CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE);
- if (duration > 0.0)
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), start_opacity,
- std::move(func)));
- curve->AddKeyframe(FloatKeyframe::Create(
- base::TimeDelta::FromSecondsD(duration), end_opacity, nullptr));
-
- int id = NextKeyframeModelId();
-
- std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), id, NextGroupId(), TargetProperty::OPACITY));
- keyframe_model->set_needs_synchronized_start_time(true);
-
- target->AddKeyframeModelForKeyframeEffect(std::move(keyframe_model),
- keyframe_effect_id);
- return id;
- }
-
- int AddAnimatedTransform(Animation* target,
- double duration,
- TransformOperations start_operations,
- TransformOperations operations,
- KeyframeEffectId keyframe_effect_id) {
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
-
- if (duration > 0.0) {
- curve->AddKeyframe(TransformKeyframe::Create(base::TimeDelta(),
- start_operations, nullptr));
- }
-
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(duration), operations, nullptr));
-
- int id = NextKeyframeModelId();
-
- std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), id, NextGroupId(), TargetProperty::TRANSFORM));
- keyframe_model->set_needs_synchronized_start_time(true);
-
- target->AddKeyframeModelForKeyframeEffect(std::move(keyframe_model),
- keyframe_effect_id);
- return id;
- }
-
- int AddAnimatedTransform(Animation* target,
- double duration,
- int delta_x,
- int delta_y,
- KeyframeEffectId keyframe_effect_id) {
- TransformOperations start_operations;
- if (duration > 0.0) {
- start_operations.AppendTranslate(0, 0, 0.0);
- }
-
- TransformOperations operations;
- operations.AppendTranslate(delta_x, delta_y, 0.0);
- return AddAnimatedTransform(target, duration, start_operations, operations,
- keyframe_effect_id);
- }
-
- int AddAnimatedFilter(Animation* target,
- double duration,
- float start_brightness,
- float end_brightness,
- KeyframeEffectId keyframe_effect_id) {
- std::unique_ptr<KeyframedFilterAnimationCurve> curve(
- KeyframedFilterAnimationCurve::Create());
-
- if (duration > 0.0) {
- FilterOperations start_filters;
- start_filters.Append(
- FilterOperation::CreateBrightnessFilter(start_brightness));
- curve->AddKeyframe(
- FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr));
- }
-
- FilterOperations filters;
- filters.Append(FilterOperation::CreateBrightnessFilter(end_brightness));
- curve->AddKeyframe(FilterKeyframe::Create(
- base::TimeDelta::FromSecondsD(duration), filters, nullptr));
-
- int id = NextKeyframeModelId();
-
- std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), id, NextGroupId(), TargetProperty::FILTER));
- keyframe_model->set_needs_synchronized_start_time(true);
-
- target->AddKeyframeModelForKeyframeEffect(std::move(keyframe_model),
- keyframe_effect_id);
- return id;
- }
-
void CheckKeyframeEffectAndTimelineNeedsPushProperties(
bool needs_push_properties,
KeyframeEffectId keyframe_effect_id) const {
@@ -150,9 +38,7 @@ class AnimationTest : public AnimationTimelinesTest {
protected:
scoped_refptr<Animation> animation_;
scoped_refptr<Animation> animation_impl_;
- int group_id_;
KeyframeEffectId keyframe_effect_id_;
- int keyframe_model_id_;
};
// See element_animations_unittest.cc for active/pending observers tests.
@@ -310,13 +196,13 @@ TEST_F(AnimationTest, PropertiesMutate) {
const double duration = 1.;
- AddOpacityTransition(animation_.get(), duration, start_opacity, end_opacity,
- false, keyframe_effect_id_);
+ AddOpacityTransitionToAnimation(animation_.get(), duration, start_opacity,
+ end_opacity, false, keyframe_effect_id_);
- AddAnimatedTransform(animation_.get(), duration, transform_x, transform_y,
- keyframe_effect_id_);
- AddAnimatedFilter(animation_.get(), duration, start_brightness,
- end_brightness, keyframe_effect_id_);
+ AddAnimatedTransformToAnimation(animation_.get(), duration, transform_x,
+ transform_y, keyframe_effect_id_);
+ AddAnimatedFilterToAnimation(animation_.get(), duration, start_brightness,
+ end_brightness, keyframe_effect_id_);
CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_);
host_->PushPropertiesTo(host_impl_);
@@ -412,10 +298,10 @@ TEST_F(AnimationTest, AttachTwoAnimationsToOneLayer) {
const double duration = 1.;
- AddOpacityTransition(animation1.get(), duration, start_opacity, end_opacity,
- false, keyframe_effect_id1);
- AddAnimatedTransform(animation2.get(), duration, transform_x, transform_y,
- keyframe_effect_id2);
+ AddOpacityTransitionToAnimation(animation1.get(), duration, start_opacity,
+ end_opacity, false, keyframe_effect_id1);
+ AddAnimatedTransformToAnimation(animation2.get(), duration, transform_x,
+ transform_y, keyframe_effect_id2);
host_->PushPropertiesTo(host_impl_);
host_impl_->ActivateAnimations();
@@ -481,10 +367,10 @@ TEST_F(AnimationTest, AddRemoveAnimationToNonAttachedAnimation) {
const float start_opacity = .7f;
const float end_opacity = .3f;
- const int filter_id = AddAnimatedFilter(animation_.get(), duration, 0.1f,
- 0.9f, keyframe_effect_id_);
- AddOpacityTransition(animation_.get(), duration, start_opacity, end_opacity,
- false, keyframe_effect_id_);
+ const int filter_id = AddAnimatedFilterToAnimation(
+ animation_.get(), duration, 0.1f, 0.9f, keyframe_effect_id_);
+ AddOpacityTransitionToAnimation(animation_.get(), duration, start_opacity,
+ end_opacity, false, keyframe_effect_id_);
EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_)
->needs_push_properties());
@@ -560,7 +446,7 @@ TEST_F(AnimationTest, AddRemoveAnimationCausesSetNeedsCommit) {
EXPECT_FALSE(client_.mutators_need_commit());
- const int keyframe_model_id = AddOpacityTransition(
+ const int keyframe_model_id = AddOpacityTransitionToAnimation(
animation_.get(), 1., .7f, .3f, false, keyframe_effect_id_);
EXPECT_TRUE(client_.mutators_need_commit());
@@ -973,10 +859,10 @@ TEST_F(AnimationTest, TickingAnimationsFromTwoKeyframeEffects) {
const double duration = 1.;
- AddOpacityTransition(animation_.get(), duration, start_opacity, end_opacity,
- false, keyframe_effect_id1);
- AddAnimatedTransform(animation_.get(), duration, transform_x, transform_y,
- keyframe_effect_id2);
+ AddOpacityTransitionToAnimation(animation_.get(), duration, start_opacity,
+ end_opacity, false, keyframe_effect_id1);
+ AddAnimatedTransformToAnimation(animation_.get(), duration, transform_x,
+ transform_y, keyframe_effect_id2);
host_->PushPropertiesTo(host_impl_);
host_impl_->ActivateAnimations();
diff --git a/chromium/cc/animation/element_animations_unittest.cc b/chromium/cc/animation/element_animations_unittest.cc
index 9cff257a6f4..beb43dbe276 100644
--- a/chromium/cc/animation/element_animations_unittest.cc
+++ b/chromium/cc/animation/element_animations_unittest.cc
@@ -294,7 +294,7 @@ TEST_F(ElementAnimationsTest,
CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
const int animation2_id = 2;
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), animation2_id, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), animation2_id, 1, TargetProperty::SCROLL_OFFSET));
animation_->AddKeyframeModel(std::move(keyframe_model));
PushProperties();
EXPECT_VECTOR2DF_EQ(provider_initial_value,
@@ -1417,7 +1417,7 @@ TEST_F(ElementAnimationsTest, Interrupt) {
std::unique_ptr<KeyframeModel> to_add(CreateKeyframeModel(
std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f)),
2, TargetProperty::OPACITY));
- animation_->AbortKeyframeModels(TargetProperty::OPACITY, false);
+ animation_->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY, false);
animation_->AddKeyframeModel(std::move(to_add));
// Since the previous animation was aborted, the new animation should start
@@ -1830,9 +1830,9 @@ TEST_F(ElementAnimationsTest, InactiveObserverGetsTicked) {
client_impl_.GetOpacity(element_id_, ElementListType::ACTIVE));
}
-// Tests that AbortKeyframeModels aborts all animations targeting the
-// specified property.
-TEST_F(ElementAnimationsTest, AbortKeyframeModels) {
+// Tests that AbortKeyframeModelsWithProperty aborts all animations targeting
+// the specified property.
+TEST_F(ElementAnimationsTest, AbortKeyframeModelsWithProperty) {
CreateTestLayer(false, false);
AttachTimelineAnimationLayer();
@@ -1875,7 +1875,7 @@ TEST_F(ElementAnimationsTest, AbortKeyframeModels) {
KeyframeModel::RUNNING,
animation_->keyframe_effect()->GetKeyframeModelById(5)->run_state());
- animation_->AbortKeyframeModels(TargetProperty::TRANSFORM, false);
+ animation_->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM, false);
// Only un-finished TRANSFORM animations should have been aborted.
EXPECT_EQ(
@@ -1913,7 +1913,7 @@ TEST_F(ElementAnimationsTest, MainThreadAbortedAnimationGetsDeleted) {
keyframe_model_id));
EXPECT_FALSE(host_->needs_push_properties());
- animation_->AbortKeyframeModels(TargetProperty::OPACITY, false);
+ animation_->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY, false);
EXPECT_EQ(KeyframeModel::ABORTED,
animation_->GetKeyframeModel(TargetProperty::OPACITY)->run_state());
EXPECT_TRUE(host_->needs_push_properties());
@@ -1955,7 +1955,8 @@ TEST_F(ElementAnimationsTest, ImplThreadAbortedAnimationGetsDeleted) {
EXPECT_TRUE(animation_impl_->keyframe_effect()->GetKeyframeModelById(
keyframe_model_id));
- animation_impl_->AbortKeyframeModels(TargetProperty::OPACITY, false);
+ animation_impl_->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY,
+ false);
EXPECT_EQ(
KeyframeModel::ABORTED,
animation_impl_->GetKeyframeModel(TargetProperty::OPACITY)->run_state());
@@ -2026,7 +2027,8 @@ TEST_F(ElementAnimationsTest, ImplThreadTakeoverAnimationGetsDeleted) {
EXPECT_TRUE(animation_impl_->keyframe_effect()->GetKeyframeModelById(
keyframe_model_id));
- animation_impl_->AbortKeyframeModels(TargetProperty::SCROLL_OFFSET, true);
+ animation_impl_->AbortKeyframeModelsWithProperty(
+ TargetProperty::SCROLL_OFFSET, true);
EXPECT_TRUE(host_impl_->needs_push_properties());
EXPECT_EQ(KeyframeModel::ABORTED_BUT_NEEDS_COMPLETION,
animation_impl_->GetKeyframeModel(TargetProperty::SCROLL_OFFSET)
@@ -2152,7 +2154,8 @@ TEST_F(ElementAnimationsTest, FinishedAndAbortedEventsForGroup) {
EXPECT_EQ(AnimationEvent::STARTED, events->events_[0].type);
EXPECT_EQ(AnimationEvent::STARTED, events->events_[1].type);
- animation_impl_->AbortKeyframeModels(TargetProperty::OPACITY, false);
+ animation_impl_->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY,
+ false);
events = CreateEventsForTesting();
animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
@@ -2877,7 +2880,8 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenTransformAnimationChanges) {
animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]);
events->events_.clear();
- animation_impl_->AbortKeyframeModels(TargetProperty::TRANSFORM, false);
+ animation_impl_->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM,
+ false);
EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
element_id_, ElementListType::PENDING));
EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
@@ -3091,7 +3095,8 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenOpacityAnimationChanges) {
animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]);
events->events_.clear();
- animation_impl_->AbortKeyframeModels(TargetProperty::OPACITY, false);
+ animation_impl_->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY,
+ false);
EXPECT_FALSE(client_impl_.GetHasPotentialOpacityAnimation(
element_id_, ElementListType::PENDING));
EXPECT_FALSE(client_impl_.GetOpacityIsCurrentlyAnimating(
@@ -3304,7 +3309,8 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenFilterAnimationChanges) {
animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]);
events->events_.clear();
- animation_impl_->AbortKeyframeModels(TargetProperty::FILTER, false);
+ animation_impl_->AbortKeyframeModelsWithProperty(TargetProperty::FILTER,
+ false);
EXPECT_FALSE(client_impl_.GetHasPotentialFilterAnimation(
element_id_, ElementListType::PENDING));
EXPECT_FALSE(client_impl_.GetFilterIsCurrentlyAnimating(
@@ -3722,7 +3728,7 @@ TEST_F(ElementAnimationsTest, RemoveAndReAddAnimationToTicking) {
// animations. Remove the animation using RemoveFromTicking().
animation_->AddKeyframeModel(CreateKeyframeModel(
std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f)),
- 2, TargetProperty::OPACITY));
+ 1, TargetProperty::OPACITY));
ASSERT_EQ(1u, host_->ticking_animations_for_testing().size());
animation_->keyframe_effect()->RemoveFromTicking();
ASSERT_EQ(0u, host_->ticking_animations_for_testing().size());
@@ -3755,5 +3761,39 @@ TEST_F(ElementAnimationsTest, TickingKeyframeModelsCount) {
EXPECT_EQ(0u, host_->CompositedAnimationsCount());
}
+// This test verifies that finished keyframe models don't get copied over to
+// impl thread.
+TEST_F(ElementAnimationsTest, FinishedKeyframeModelsNotCopiedToImpl) {
+ CreateTestLayer(false, false);
+ AttachTimelineAnimationLayer();
+ CreateImplTimelineAndAnimation();
+
+ animation_->AddKeyframeModel(KeyframeModel::Create(
+ std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1.0)), 1, 1,
+ TargetProperty::TRANSFORM));
+ animation_->AddKeyframeModel(KeyframeModel::Create(
+ std::unique_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)),
+ 2, 2, TargetProperty::OPACITY));
+
+ // Finish the first keyframe model.
+ animation_->Tick(kInitialTickTime);
+ animation_->UpdateState(true, nullptr);
+ animation_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
+ animation_->UpdateState(true, nullptr);
+
+ EXPECT_EQ(
+ KeyframeModel::FINISHED,
+ animation_->keyframe_effect()->GetKeyframeModelById(1)->run_state());
+ EXPECT_EQ(
+ KeyframeModel::RUNNING,
+ animation_->keyframe_effect()->GetKeyframeModelById(2)->run_state());
+
+ PushProperties();
+
+ // Finished keyframe model doesn't get copied to impl thread.
+ EXPECT_FALSE(animation_impl_->keyframe_effect()->GetKeyframeModelById(1));
+ EXPECT_TRUE(animation_impl_->keyframe_effect()->GetKeyframeModelById(2));
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/animation/keyframe_effect.cc b/chromium/cc/animation/keyframe_effect.cc
index 9b01eda5754..15ef5feccc4 100644
--- a/chromium/cc/animation/keyframe_effect.cc
+++ b/chromium/cc/animation/keyframe_effect.cc
@@ -221,11 +221,8 @@ void KeyframeEffect::UpdateTickingState(UpdateTickingType type) {
}
void KeyframeEffect::Pause(base::TimeDelta pause_offset) {
- for (auto& keyframe_model : keyframe_models_) {
- base::TimeTicks pause_time = keyframe_model->time_offset() +
- keyframe_model->start_time() + pause_offset;
- keyframe_model->SetRunState(KeyframeModel::PAUSED, pause_time);
- }
+ for (auto& keyframe_model : keyframe_models_)
+ keyframe_model->Pause(pause_offset);
if (has_bound_element_animations()) {
animation_->SetNeedsCommit();
@@ -235,12 +232,20 @@ void KeyframeEffect::Pause(base::TimeDelta pause_offset) {
void KeyframeEffect::AddKeyframeModel(
std::unique_ptr<KeyframeModel> keyframe_model) {
- AnimationHost* animation_host = animation_->animation_host();
DCHECK(keyframe_model->target_property_id() !=
TargetProperty::SCROLL_OFFSET ||
- (animation_host && animation_host->SupportsScrollAnimations()));
+ (animation_->animation_host()->SupportsScrollAnimations()));
DCHECK(!keyframe_model->is_impl_only() ||
keyframe_model->target_property_id() == TargetProperty::SCROLL_OFFSET);
+ // This is to make sure that keyframe models in the same group, i.e., start
+ // together, don't animate the same property.
+ DCHECK(std::none_of(
+ keyframe_models_.begin(), keyframe_models_.end(),
+ [&](const auto& existing_keyframe_model) {
+ return keyframe_model->target_property_id() ==
+ existing_keyframe_model->target_property_id() &&
+ keyframe_model->group() == existing_keyframe_model->group();
+ }));
keyframe_models_.push_back(std::move(keyframe_model));
@@ -252,12 +257,11 @@ void KeyframeEffect::AddKeyframeModel(
void KeyframeEffect::PauseKeyframeModel(int keyframe_model_id,
double time_offset) {
- const base::TimeDelta time_delta = base::TimeDelta::FromSecondsD(time_offset);
+ const base::TimeDelta pause_offset =
+ base::TimeDelta::FromSecondsD(time_offset);
for (auto& keyframe_model : keyframe_models_) {
if (keyframe_model->id() == keyframe_model_id) {
- keyframe_model->SetRunState(KeyframeModel::PAUSED,
- time_delta + keyframe_model->start_time() +
- keyframe_model->time_offset());
+ keyframe_model->Pause(pause_offset);
}
}
@@ -315,8 +319,9 @@ void KeyframeEffect::AbortKeyframeModel(int keyframe_model_id) {
}
}
-void KeyframeEffect::AbortKeyframeModels(TargetProperty::Type target_property,
- bool needs_completion) {
+void KeyframeEffect::AbortKeyframeModelsWithProperty(
+ TargetProperty::Type target_property,
+ bool needs_completion) {
if (needs_completion)
DCHECK(target_property == TargetProperty::SCROLL_OFFSET);
@@ -681,6 +686,11 @@ void KeyframeEffect::PushNewKeyframeModelsToImplThread(
// Any new KeyframeModels owned by the main thread's Animation are
// cloned and added to the impl thread's Animation.
for (const auto& keyframe_model : keyframe_models_) {
+ // If the keyframe_model is finished, do not copy it over to impl since the
+ // impl instance, if there was one, was just removed in
+ // |RemoveKeyframeModelsCompletedOnMainThread|.
+ if (keyframe_model->is_finished())
+ continue;
// If the keyframe_model is already running on the impl thread, there is no
// need to copy it over.
if (keyframe_effect_impl->GetKeyframeModelById(keyframe_model->id()))
@@ -785,12 +795,8 @@ void KeyframeEffect::PushPropertiesTo(KeyframeEffect* keyframe_effect_impl) {
// aborted KeyframeModels and pushing any new animations.
MarkAbortedKeyframeModelsForDeletion(keyframe_effect_impl);
PurgeKeyframeModelsMarkedForDeletion(/* impl_only */ false);
- PushNewKeyframeModelsToImplThread(keyframe_effect_impl);
-
- // Remove finished impl side KeyframeModels only after pushing,
- // and only after the KeyframeModels are deleted on the main thread
- // this insures we will never push a keyframe model twice.
RemoveKeyframeModelsCompletedOnMainThread(keyframe_effect_impl);
+ PushNewKeyframeModelsToImplThread(keyframe_effect_impl);
// Now that the keyframe model lists are synchronized, push the properties for
// the individual KeyframeModels.
diff --git a/chromium/cc/animation/keyframe_effect.h b/chromium/cc/animation/keyframe_effect.h
index 4ee5176e517..0c33cb7db6d 100644
--- a/chromium/cc/animation/keyframe_effect.h
+++ b/chromium/cc/animation/keyframe_effect.h
@@ -23,7 +23,6 @@
namespace cc {
class Animation;
-class KeyframeModel;
struct PropertyAnimationState;
typedef size_t KeyframeEffectId;
@@ -42,7 +41,7 @@ typedef size_t KeyframeEffectId;
class CC_ANIMATION_EXPORT KeyframeEffect {
public:
explicit KeyframeEffect(KeyframeEffectId id);
- ~KeyframeEffect();
+ virtual ~KeyframeEffect();
static std::unique_ptr<KeyframeEffect> Create(KeyframeEffectId id);
std::unique_ptr<KeyframeEffect> CreateImplInstance() const;
@@ -81,7 +80,7 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
void AttachElement(ElementId element_id);
void DetachElement();
- void Tick(base::TimeTicks monotonic_time);
+ virtual void Tick(base::TimeTicks monotonic_time);
static void TickKeyframeModel(base::TimeTicks monotonic_time,
KeyframeModel* keyframe_model,
AnimationTarget* target);
@@ -97,8 +96,8 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
void PauseKeyframeModel(int keyframe_model_id, double time_offset);
void RemoveKeyframeModel(int keyframe_model_id);
void AbortKeyframeModel(int keyframe_model_id);
- void AbortKeyframeModels(TargetProperty::Type target_property,
- bool needs_completion);
+ void AbortKeyframeModelsWithProperty(TargetProperty::Type target_property,
+ bool needs_completion);
void ActivateKeyframeEffects();
diff --git a/chromium/cc/animation/keyframe_model.cc b/chromium/cc/animation/keyframe_model.cc
index d8495a62ff1..10556098fc8 100644
--- a/chromium/cc/animation/keyframe_model.cc
+++ b/chromium/cc/animation/keyframe_model.cc
@@ -66,7 +66,7 @@ std::unique_ptr<KeyframeModel> KeyframeModel::CreateImplInstance(
to_return->iteration_start_ = iteration_start_;
to_return->start_time_ = start_time_;
to_return->pause_time_ = pause_time_;
- to_return->total_paused_time_ = total_paused_time_;
+ to_return->total_paused_duration_ = total_paused_duration_;
to_return->time_offset_ = time_offset_;
to_return->direction_ = direction_;
to_return->playback_rate_ = playback_rate_;
@@ -121,7 +121,7 @@ void KeyframeModel::SetRunState(RunState run_state,
const char* old_run_state_name = s_runStateNames[run_state_];
if (run_state == RUNNING && run_state_ == PAUSED)
- total_paused_time_ += (monotonic_time - pause_time_);
+ total_paused_duration_ += (monotonic_time - pause_time_);
else if (run_state == PAUSED)
pause_time_ = monotonic_time;
run_state_ = run_state;
@@ -140,6 +140,18 @@ void KeyframeModel::SetRunState(RunState run_state,
TRACE_STR_COPY(name_buffer), "State", TRACE_STR_COPY(state_buffer));
}
+void KeyframeModel::Pause(base::TimeDelta pause_offset) {
+ // Convert pause offset to monotonic time.
+
+ // TODO(crbug.com/840364): This conversion is incorrect. pause_offset is
+ // actually a local time so to convert it to monotonic time we should include
+ // total_paused_duration_ but exclude time_offset. The current calculation is
+ // is incorrect for animations that have start-delay or are paused and
+ // unpaused multiple times.
+ base::TimeTicks monotonic_time = pause_offset + start_time_ + time_offset_;
+ SetRunState(PAUSED, monotonic_time);
+}
+
bool KeyframeModel::IsFinishedAt(base::TimeTicks monotonic_time) const {
if (is_finished())
return true;
@@ -152,39 +164,42 @@ bool KeyframeModel::IsFinishedAt(base::TimeTicks monotonic_time) const {
return run_state_ == RUNNING && iterations_ >= 0 &&
(curve_->Duration() * (iterations_ / std::abs(playback_rate_))) <=
- (monotonic_time + time_offset_ - start_time_ - total_paused_time_);
+ (ConvertMonotonicTimeToLocalTime(monotonic_time) + time_offset_);
}
bool KeyframeModel::InEffect(base::TimeTicks monotonic_time) const {
- return ConvertToActiveTime(monotonic_time) >= base::TimeDelta() ||
+ return ConvertMonotonicTimeToLocalTime(monotonic_time) + time_offset_ >=
+ base::TimeDelta() ||
(fill_mode_ == FillMode::BOTH || fill_mode_ == FillMode::BACKWARDS);
}
-base::TimeDelta KeyframeModel::ConvertToActiveTime(
+base::TimeDelta KeyframeModel::ConvertMonotonicTimeToLocalTime(
base::TimeTicks monotonic_time) const {
- // If we're just starting or we're waiting on receiving a start time,
- // time is 'stuck' at the initial state.
+ // When waiting on receiving a start time, then our global clock is 'stuck' at
+ // the initial state.
if ((run_state_ == STARTING && !has_set_start_time()) ||
- needs_synchronized_start_time()) {
- return time_offset_;
- }
-
- // Compute active time. If we're paused, time is 'stuck' at the pause time.
- base::TimeTicks active_time =
- (run_state_ == PAUSED) ? pause_time_ : (monotonic_time + time_offset_);
+ needs_synchronized_start_time())
+ return base::TimeDelta();
- // Returned time should always be relative to the start time and should
- // subtract all time spent paused.
- return active_time - start_time_ - total_paused_time_;
+ // If we're paused, time is 'stuck' at the pause time.
+ base::TimeTicks time =
+ (run_state_ == PAUSED) ? pause_time_ - time_offset_ : monotonic_time;
+ return time - start_time_ - total_paused_duration_;
}
base::TimeDelta KeyframeModel::TrimTimeToCurrentIteration(
base::TimeTicks monotonic_time) const {
+ base::TimeDelta local_time = ConvertMonotonicTimeToLocalTime(monotonic_time);
+ return TrimLocalTimeToCurrentIteration(local_time);
+}
+
+base::TimeDelta KeyframeModel::TrimLocalTimeToCurrentIteration(
+ base::TimeDelta local_time) const {
// Check for valid parameters
DCHECK(playback_rate_);
DCHECK_GE(iteration_start_, 0);
- base::TimeDelta active_time = ConvertToActiveTime(monotonic_time);
+ base::TimeDelta active_time = local_time + time_offset_;
base::TimeDelta start_offset = curve_->Duration() * iteration_start_;
// Return start offset if we are before the start of the keyframe model
@@ -254,7 +269,7 @@ void KeyframeModel::PushPropertiesTo(KeyframeModel* other) const {
other->run_state_ == KeyframeModel::PAUSED) {
other->run_state_ = run_state_;
other->pause_time_ = pause_time_;
- other->total_paused_time_ = total_paused_time_;
+ other->total_paused_duration_ = total_paused_duration_;
}
}
diff --git a/chromium/cc/animation/keyframe_model.h b/chromium/cc/animation/keyframe_model.h
index 9d770995dd8..329a986253f 100644
--- a/chromium/cc/animation/keyframe_model.h
+++ b/chromium/cc/animation/keyframe_model.h
@@ -95,6 +95,9 @@ class CC_ANIMATION_EXPORT KeyframeModel {
time_offset_ = monotonic_time;
}
+ // Pause the keyframe effect at local time |pause_offset|.
+ void Pause(base::TimeDelta pause_offset);
+
Direction direction() { return direction_; }
void set_direction(Direction direction) { direction_ = direction; }
@@ -168,7 +171,35 @@ class CC_ANIMATION_EXPORT KeyframeModel {
int group_id,
int target_property_id);
- base::TimeDelta ConvertToActiveTime(base::TimeTicks monotonic_time) const;
+ // Return local time for this keyframe model given the absolute monotonic
+ // time.
+ //
+ // Local time represents the time value that is used to tick this keyframe
+ // model and is relative to its start time. It is closely related to the local
+ // time concept in web animations [1]. It is:
+ // - for playing animation : wall time - start time - paused duration
+ // - for paused animation : paused time
+ // - otherwise : zero
+ //
+ // Here is small diagram that shows how active, local, and monotonic times
+ // relate to each other and to the run state.
+ //
+ // run state Starting (R)unning Paused (R) Paused (R) Finished
+ // ^ ^
+ // | |
+ // monotonic time ------------------------------------------------->
+ // | |
+ // local time +-----------------+ +---+ +--------->
+ // | |
+ // active time + +------+ +---+ +------+
+ // (-offset)
+ //
+ // [1] https://drafts.csswg.org/web-animations/#local-time-section
+ base::TimeDelta ConvertMonotonicTimeToLocalTime(
+ base::TimeTicks monotonic_time) const;
+
+ base::TimeDelta TrimLocalTimeToCurrentIteration(
+ base::TimeDelta local_time) const;
std::unique_ptr<AnimationCurve> curve_;
@@ -199,12 +230,12 @@ class CC_ANIMATION_EXPORT KeyframeModel {
bool needs_synchronized_start_time_;
bool received_finished_event_;
- // These are used in TrimTimeToCurrentIteration to account for time
+ // These are used when converting monotonic to local time to account for time
// spent while paused. This is not included in AnimationState since it
// there is absolutely no need for clients of this controller to know
// about these values.
base::TimeTicks pause_time_;
- base::TimeDelta total_paused_time_;
+ base::TimeDelta total_paused_duration_;
// KeyframeModels lead dual lives. An active keyframe model will be
// conceptually owned by two controllers, one on the impl thread and one on
diff --git a/chromium/cc/animation/scroll_offset_animations_impl.cc b/chromium/cc/animation/scroll_offset_animations_impl.cc
index 9e0b9aa1025..2e1a274e925 100644
--- a/chromium/cc/animation/scroll_offset_animations_impl.cc
+++ b/chromium/cc/animation/scroll_offset_animations_impl.cc
@@ -4,6 +4,8 @@
#include "cc/animation/scroll_offset_animations_impl.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_timeline.h"
@@ -44,6 +46,8 @@ void ScrollOffsetAnimationsImpl::ScrollAnimationCreate(
CubicBezierTimingFunction::EaseType::EASE_IN_OUT),
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA);
curve->SetInitialValue(current_offset, delayed_by);
+ TRACE_EVENT_INSTANT1("cc", "ScrollAnimationCreate", TRACE_EVENT_SCOPE_THREAD,
+ "Duration", curve->Duration().InMillisecondsF());
std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create(
std::move(curve), AnimationIdProvider::NextKeyframeModelId(),
@@ -66,8 +70,11 @@ bool ScrollOffsetAnimationsImpl::ScrollAnimationUpdateTarget(
base::TimeTicks frame_monotonic_time,
base::TimeDelta delayed_by) {
DCHECK(scroll_offset_animation_);
- if (!scroll_offset_animation_->has_element_animations())
+ if (!scroll_offset_animation_->has_element_animations()) {
+ TRACE_EVENT_INSTANT0("cc", "No element animation exists",
+ TRACE_EVENT_SCOPE_THREAD);
return false;
+ }
DCHECK_EQ(element_id, scroll_offset_animation_->element_id());
@@ -75,6 +82,8 @@ bool ScrollOffsetAnimationsImpl::ScrollAnimationUpdateTarget(
scroll_offset_animation_->GetKeyframeModel(TargetProperty::SCROLL_OFFSET);
if (!keyframe_model) {
scroll_offset_animation_->DetachElement();
+ TRACE_EVENT_INSTANT0("cc", "No keyframe model exists",
+ TRACE_EVENT_SCOPE_THREAD);
return false;
}
if (scroll_delta.IsZero())
@@ -102,6 +111,9 @@ bool ScrollOffsetAnimationsImpl::ScrollAnimationUpdateTarget(
trimmed -= delayed_by;
curve->UpdateTarget(trimmed.InSecondsF(), new_target);
+ TRACE_EVENT_INSTANT1("cc", "ScrollAnimationUpdateTarget",
+ TRACE_EVENT_SCOPE_THREAD, "UpdatedDuration",
+ curve->Duration().InMillisecondsF());
return true;
}
@@ -143,8 +155,8 @@ void ScrollOffsetAnimationsImpl::ScrollAnimationApplyAdjustment(
void ScrollOffsetAnimationsImpl::ScrollAnimationAbort(bool needs_completion) {
DCHECK(scroll_offset_animation_);
- scroll_offset_animation_->AbortKeyframeModels(TargetProperty::SCROLL_OFFSET,
- needs_completion);
+ scroll_offset_animation_->AbortKeyframeModelsWithProperty(
+ TargetProperty::SCROLL_OFFSET, needs_completion);
}
void ScrollOffsetAnimationsImpl::NotifyAnimationFinished(
diff --git a/chromium/cc/animation/scroll_timeline.cc b/chromium/cc/animation/scroll_timeline.cc
index a880877b605..ee02fb5cab4 100644
--- a/chromium/cc/animation/scroll_timeline.cc
+++ b/chromium/cc/animation/scroll_timeline.cc
@@ -11,31 +11,44 @@
namespace cc {
-ScrollTimeline::ScrollTimeline(ElementId scroller_id,
+ScrollTimeline::ScrollTimeline(base::Optional<ElementId> scroller_id,
ScrollDirection orientation,
double time_range)
- : scroller_id_(scroller_id),
+ : active_id_(),
+ pending_id_(scroller_id),
orientation_(orientation),
time_range_(time_range) {}
+ScrollTimeline::~ScrollTimeline() {}
+
std::unique_ptr<ScrollTimeline> ScrollTimeline::CreateImplInstance() const {
- return std::make_unique<ScrollTimeline>(scroller_id_, orientation_,
+ return std::make_unique<ScrollTimeline>(pending_id_, orientation_,
time_range_);
}
-double ScrollTimeline::CurrentTime(const ScrollTree& scroll_tree) const {
- // If the scroller isn't in the ScrollTree, the element either no longer
- // exists or is not currently scrollable. By the spec, return an unresolved
- // time value.
- if (!scroll_tree.FindNodeFromElementId(scroller_id_))
+double ScrollTimeline::CurrentTime(const ScrollTree& scroll_tree,
+ bool is_active_tree) const {
+ // We may be asked for the CurrentTime before the pending tree with our
+ // scroller has been activated, or after the scroller has been removed (e.g.
+ // if it is no longer composited). In these cases the best we can do is to
+ // return an unresolved time value.
+ if ((is_active_tree && !active_id_) || (!is_active_tree && !pending_id_))
return std::numeric_limits<double>::quiet_NaN();
- gfx::ScrollOffset offset = scroll_tree.current_scroll_offset(scroller_id_);
+ ElementId scroller_id =
+ is_active_tree ? active_id_.value() : pending_id_.value();
+
+ // The scroller may not be in the ScrollTree if it is not currently scrollable
+ // (e.g. has overflow: visible). By the spec, return an unresolved time value.
+ if (!scroll_tree.FindNodeFromElementId(scroller_id))
+ return std::numeric_limits<double>::quiet_NaN();
+
+ gfx::ScrollOffset offset = scroll_tree.current_scroll_offset(scroller_id);
DCHECK_GE(offset.x(), 0);
DCHECK_GE(offset.y(), 0);
gfx::ScrollOffset scroll_dimensions = scroll_tree.MaxScrollOffset(
- scroll_tree.FindNodeFromElementId(scroller_id_)->id);
+ scroll_tree.FindNodeFromElementId(scroller_id)->id);
double current_offset = (orientation_ == Vertical) ? offset.y() : offset.x();
double max_offset = (orientation_ == Vertical) ? scroll_dimensions.y()
@@ -57,4 +70,21 @@ double ScrollTimeline::CurrentTime(const ScrollTree& scroll_tree) const {
return (std::abs(current_offset) / max_offset) * time_range_;
}
+void ScrollTimeline::PushPropertiesTo(ScrollTimeline* impl_timeline) {
+ DCHECK(impl_timeline);
+ impl_timeline->pending_id_ = pending_id_;
+}
+
+void ScrollTimeline::PromoteScrollTimelinePendingToActive() {
+ active_id_ = pending_id_;
+}
+
+void ScrollTimeline::SetScrollerId(base::Optional<ElementId> pending_id) {
+ // When the scroller id changes it will first be modified in the pending tree.
+ // Then later (when the pending tree is promoted to active)
+ // |PromoteScrollTimelinePendingToActive| will be called and will set the
+ // |active_id_|.
+ pending_id_ = pending_id;
+}
+
} // namespace cc
diff --git a/chromium/cc/animation/scroll_timeline.h b/chromium/cc/animation/scroll_timeline.h
index 7389d4df479..1efd2a77963 100644
--- a/chromium/cc/animation/scroll_timeline.h
+++ b/chromium/cc/animation/scroll_timeline.h
@@ -5,6 +5,7 @@
#ifndef CC_ANIMATION_SCROLL_TIMELINE_H_
#define CC_ANIMATION_SCROLL_TIMELINE_H_
+#include "base/optional.h"
#include "cc/animation/animation_export.h"
#include "cc/trees/element_id.h"
@@ -26,10 +27,10 @@ class CC_ANIMATION_EXPORT ScrollTimeline {
public:
enum ScrollDirection { Horizontal, Vertical };
- ScrollTimeline(ElementId scroller_id,
+ ScrollTimeline(base::Optional<ElementId> scroller_id,
ScrollDirection orientation,
double time_range);
- virtual ~ScrollTimeline() {}
+ virtual ~ScrollTimeline();
// Create a copy of this ScrollTimeline intended for the impl thread in the
// compositor.
@@ -38,13 +39,21 @@ class CC_ANIMATION_EXPORT ScrollTimeline {
// Calculate the current time of the ScrollTimeline. This is either a double
// value or std::numeric_limits<double>::quiet_NaN() if the current time is
// unresolved.
- virtual double CurrentTime(const ScrollTree& scroll_tree) const;
+ virtual double CurrentTime(const ScrollTree& scroll_tree,
+ bool is_active_tree) const;
+
+ void SetScrollerId(base::Optional<ElementId> scroller_id);
+
+ void PushPropertiesTo(ScrollTimeline* impl_timeline);
+
+ void PromoteScrollTimelinePendingToActive();
private:
- // The scroller which this ScrollTimeline is based on. It is expected that
- // this scroller will exist in the scroll property tree, or otherwise calling
- // CurrentTime will fail.
- ElementId scroller_id_;
+ // The scroller which this ScrollTimeline is based on. The same underlying
+ // scroll source may have different ids in the pending and active tree (see
+ // http://crbug.com/847588).
+ base::Optional<ElementId> active_id_;
+ base::Optional<ElementId> pending_id_;
// The orientation of the ScrollTimeline indicates which axis of the scroller
// it should base its current time on - either the horizontal or vertical.
diff --git a/chromium/cc/animation/scroll_timeline_unittest.cc b/chromium/cc/animation/scroll_timeline_unittest.cc
index 4b410137b97..3fc5cbe6306 100644
--- a/chromium/cc/animation/scroll_timeline_unittest.cc
+++ b/chromium/cc/animation/scroll_timeline_unittest.cc
@@ -17,7 +17,7 @@ class ScrollTimelineTest : public ::testing::Test {
// For simplicity we make the property_tree main thread; this avoids the
// need to deal with the synced scroll offset code.
property_trees_.is_main_thread = true;
- property_trees_.is_active = true;
+ property_trees_.is_active = false;
// We add a single node that is scrolling a 550x1100 contents inside a
// 50x100 container.
@@ -55,16 +55,16 @@ TEST_F(ScrollTimelineTest, BasicCurrentTimeCalculations) {
// Unscrolled, both timelines should read a current time of 0.
scroll_tree().SetScrollOffset(scroller_id(), gfx::ScrollOffset());
- EXPECT_FLOAT_EQ(0, vertical_timeline.CurrentTime(scroll_tree()));
- EXPECT_FLOAT_EQ(0, horizontal_timeline.CurrentTime(scroll_tree()));
+ EXPECT_FLOAT_EQ(0, vertical_timeline.CurrentTime(scroll_tree(), false));
+ EXPECT_FLOAT_EQ(0, horizontal_timeline.CurrentTime(scroll_tree(), false));
// Now do some scrolling and make sure that the ScrollTimelines update.
scroll_tree().SetScrollOffset(scroller_id(), gfx::ScrollOffset(75, 50));
// As noted above, we have mapped the time range such that current time should
// just be the scroll offset.
- EXPECT_FLOAT_EQ(50, vertical_timeline.CurrentTime(scroll_tree()));
- EXPECT_FLOAT_EQ(75, horizontal_timeline.CurrentTime(scroll_tree()));
+ EXPECT_FLOAT_EQ(50, vertical_timeline.CurrentTime(scroll_tree(), false));
+ EXPECT_FLOAT_EQ(75, horizontal_timeline.CurrentTime(scroll_tree(), false));
}
TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForTimeRange) {
@@ -75,7 +75,60 @@ TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForTimeRange) {
double halfwayY = (content_size().height() - container_size().height()) / 2.;
scroll_tree().SetScrollOffset(scroller_id(), gfx::ScrollOffset(0, halfwayY));
- EXPECT_FLOAT_EQ(50, timeline.CurrentTime(scroll_tree()));
+ EXPECT_FLOAT_EQ(50, timeline.CurrentTime(scroll_tree(), false));
+}
+
+// This test ensures that the ScrollTimeline's active scroller id is correct. We
+// had a few crashes caused by assuming that the id would be available in the
+// active tree before the activation happened; see http://crbug.com/853231
+TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) {
+ PropertyTrees pending_tree;
+ PropertyTrees active_tree;
+
+ pending_tree.is_active = false;
+ active_tree.is_active = true;
+
+ // For simplicity we pretend the trees are main thread; this avoids the need
+ // to deal with the synced scroll offset code.
+ pending_tree.is_main_thread = true;
+ active_tree.is_main_thread = true;
+
+ // Initially only the pending tree has the scroll node.
+ ElementId scroller_id(1);
+ ScrollNode node;
+ node.scrollable = true;
+ node.bounds = content_size();
+ node.container_bounds = container_size();
+
+ int node_id = pending_tree.scroll_tree.Insert(node, 0);
+ pending_tree.element_id_to_scroll_node_index[scroller_id] = node_id;
+
+ double halfwayY = (content_size().height() - container_size().height()) / 2.;
+ pending_tree.scroll_tree.SetScrollOffset(scroller_id,
+ gfx::ScrollOffset(0, halfwayY));
+
+ ScrollTimeline main_timeline(scroller_id, ScrollTimeline::Vertical, 100);
+
+ // Now create an impl version of the ScrollTimeline. Initilly this should only
+ // have a pending scroller id, as the active tree may not yet have the
+ // scroller in it (as in this case).
+ std::unique_ptr<ScrollTimeline> impl_timeline =
+ main_timeline.CreateImplInstance();
+
+ EXPECT_TRUE(
+ std::isnan(impl_timeline->CurrentTime(active_tree.scroll_tree, true)));
+ EXPECT_FLOAT_EQ(50,
+ impl_timeline->CurrentTime(pending_tree.scroll_tree, false));
+
+ // Now fake a tree activation; this should cause the ScrollTimeline to update
+ // its active scroller id. Note that we deliberately pass in the pending_tree
+ // and just claim it is the active tree; this avoids needing to properly
+ // implement tree swapping just for the test.
+ impl_timeline->PromoteScrollTimelinePendingToActive();
+ EXPECT_FLOAT_EQ(50,
+ impl_timeline->CurrentTime(pending_tree.scroll_tree, true));
+ EXPECT_FLOAT_EQ(50,
+ impl_timeline->CurrentTime(pending_tree.scroll_tree, false));
}
} // namespace cc
diff --git a/chromium/cc/animation/single_keyframe_effect_animation.cc b/chromium/cc/animation/single_keyframe_effect_animation.cc
index 4c5d3eb0da0..d102c3924b3 100644
--- a/chromium/cc/animation/single_keyframe_effect_animation.cc
+++ b/chromium/cc/animation/single_keyframe_effect_animation.cc
@@ -26,17 +26,24 @@ SingleKeyframeEffectAnimation::Create(int id) {
}
SingleKeyframeEffectAnimation::SingleKeyframeEffectAnimation(int id)
- : Animation(id) {
- DCHECK(id_);
- AddKeyframeEffect(std::make_unique<KeyframeEffect>(NextKeyframeEffectId()));
-}
+ : SingleKeyframeEffectAnimation(id, nullptr) {}
SingleKeyframeEffectAnimation::SingleKeyframeEffectAnimation(
int id,
size_t keyframe_effect_id)
+ : SingleKeyframeEffectAnimation(
+ id,
+ std::make_unique<KeyframeEffect>(keyframe_effect_id)) {}
+
+SingleKeyframeEffectAnimation::SingleKeyframeEffectAnimation(
+ int id,
+ std::unique_ptr<KeyframeEffect> keyframe_effect)
: Animation(id) {
DCHECK(id_);
- AddKeyframeEffect(std::make_unique<KeyframeEffect>(keyframe_effect_id));
+ if (!keyframe_effect)
+ keyframe_effect.reset(new KeyframeEffect(NextKeyframeEffectId()));
+
+ AddKeyframeEffect(std::move(keyframe_effect));
}
SingleKeyframeEffectAnimation::~SingleKeyframeEffectAnimation() {}
diff --git a/chromium/cc/animation/single_keyframe_effect_animation.h b/chromium/cc/animation/single_keyframe_effect_animation.h
index c406892e415..6baeb7669c8 100644
--- a/chromium/cc/animation/single_keyframe_effect_animation.h
+++ b/chromium/cc/animation/single_keyframe_effect_animation.h
@@ -44,7 +44,7 @@ class CC_ANIMATION_EXPORT SingleKeyframeEffectAnimation : public Animation {
KeyframeEffect* keyframe_effect() const;
void AddKeyframeModel(std::unique_ptr<KeyframeModel> keyframe_model);
void PauseKeyframeModel(int keyframe_model_id, double time_offset);
- void RemoveKeyframeModel(int keyframe_model_id);
+ virtual void RemoveKeyframeModel(int keyframe_model_id);
void AbortKeyframeModel(int keyframe_model_id);
bool NotifyKeyframeModelFinishedForTesting(
@@ -60,6 +60,9 @@ class CC_ANIMATION_EXPORT SingleKeyframeEffectAnimation : public Animation {
protected:
explicit SingleKeyframeEffectAnimation(int id);
explicit SingleKeyframeEffectAnimation(int id, size_t keyframe_effect_id);
+ explicit SingleKeyframeEffectAnimation(int id,
+ std::unique_ptr<KeyframeEffect>);
+
~SingleKeyframeEffectAnimation() override;
DISALLOW_COPY_AND_ASSIGN(SingleKeyframeEffectAnimation);
diff --git a/chromium/cc/animation/worklet_animation.cc b/chromium/cc/animation/worklet_animation.cc
index a905b94ce12..34a9746df3c 100644
--- a/chromium/cc/animation/worklet_animation.cc
+++ b/chromium/cc/animation/worklet_animation.cc
@@ -4,29 +4,57 @@
#include "cc/animation/worklet_animation.h"
+#include "cc/animation/animation_id_provider.h"
+#include "cc/animation/keyframe_effect.h"
#include "cc/animation/scroll_timeline.h"
+#include "cc/trees/animation_options.h"
namespace cc {
WorkletAnimation::WorkletAnimation(
- int id,
+ int cc_animation_id,
+ WorkletAnimationId worklet_animation_id,
const std::string& name,
std::unique_ptr<ScrollTimeline> scroll_timeline,
+ std::unique_ptr<AnimationOptions> options,
bool is_controlling_instance)
- : SingleKeyframeEffectAnimation(id),
+ : WorkletAnimation(cc_animation_id,
+ worklet_animation_id,
+ name,
+ std::move(scroll_timeline),
+ std::move(options),
+ is_controlling_instance,
+ nullptr) {}
+
+WorkletAnimation::WorkletAnimation(
+ int cc_animation_id,
+ WorkletAnimationId worklet_animation_id,
+ const std::string& name,
+ std::unique_ptr<ScrollTimeline> scroll_timeline,
+ std::unique_ptr<AnimationOptions> options,
+ bool is_controlling_instance,
+ std::unique_ptr<KeyframeEffect> effect)
+ : SingleKeyframeEffectAnimation(cc_animation_id, std::move(effect)),
+ worklet_animation_id_(worklet_animation_id),
name_(name),
scroll_timeline_(std::move(scroll_timeline)),
+ options_(std::move(options)),
+ local_time_(base::nullopt),
+ start_time_(base::nullopt),
last_current_time_(base::nullopt),
+ state_(State::PENDING),
is_impl_instance_(is_controlling_instance) {}
WorkletAnimation::~WorkletAnimation() = default;
scoped_refptr<WorkletAnimation> WorkletAnimation::Create(
- int id,
+ WorkletAnimationId worklet_animation_id,
const std::string& name,
- std::unique_ptr<ScrollTimeline> scroll_timeline) {
- return WrapRefCounted(
- new WorkletAnimation(id, name, std::move(scroll_timeline), false));
+ std::unique_ptr<ScrollTimeline> scroll_timeline,
+ std::unique_ptr<AnimationOptions> options) {
+ return WrapRefCounted(new WorkletAnimation(
+ AnimationIdProvider::NextAnimationId(), worklet_animation_id, name,
+ std::move(scroll_timeline), std::move(options), false));
}
scoped_refptr<Animation> WorkletAnimation::CreateImplInstance() const {
@@ -34,13 +62,18 @@ scoped_refptr<Animation> WorkletAnimation::CreateImplInstance() const {
if (scroll_timeline_)
impl_timeline = scroll_timeline_->CreateImplInstance();
- return WrapRefCounted(
- new WorkletAnimation(id(), name(), std::move(impl_timeline), true));
+ return WrapRefCounted(new WorkletAnimation(id(), worklet_animation_id_,
+ name(), std::move(impl_timeline),
+ CloneOptions(), true));
}
-void WorkletAnimation::SetLocalTime(base::TimeDelta local_time) {
- local_time_ = local_time;
- SetNeedsPushProperties();
+void WorkletAnimation::PushPropertiesTo(Animation* animation_impl) {
+ Animation::PushPropertiesTo(animation_impl);
+ WorkletAnimation* worklet_animation_impl = ToWorkletAnimation(animation_impl);
+ if (scroll_timeline_) {
+ scroll_timeline_->PushPropertiesTo(
+ worklet_animation_impl->scroll_timeline_.get());
+ }
}
void WorkletAnimation::Tick(base::TimeTicks monotonic_time) {
@@ -48,36 +81,102 @@ void WorkletAnimation::Tick(base::TimeTicks monotonic_time) {
// skip ticking all animations on main thread in http://crbug.com/762717.
if (!is_impl_instance_)
return;
+ if (!local_time_.has_value())
+ return;
// As the output of a WorkletAnimation is driven by a script-provided local
// time, we don't want the underlying effect to participate in the normal
// animations lifecycle. To avoid this we pause the underlying keyframe effect
// at the local time obtained from the user script - essentially turning each
// call to |WorkletAnimation::Tick| into a seek in the effect.
- keyframe_effect()->Pause(local_time_);
+ keyframe_effect()->Pause(local_time_.value());
keyframe_effect()->Tick(monotonic_time);
}
-// TODO(crbug.com/780151): The current time returned should be an offset against
-// the animation's start time and based on the playback rate, not just the
-// timeline time directly.
-double WorkletAnimation::CurrentTime(base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree) {
- if (scroll_timeline_) {
- return scroll_timeline_->CurrentTime(scroll_tree);
+void WorkletAnimation::UpdateInputState(MutatorInputState* input_state,
+ base::TimeTicks monotonic_time,
+ const ScrollTree& scroll_tree,
+ bool is_active_tree) {
+ // Record the monotonic time to be the start time first time state is
+ // generated. This time is used as the origin for computing the current time.
+ if (!start_time_.has_value())
+ start_time_ = monotonic_time;
+
+ // Skip running worklet animations with unchanged input time and reuse
+ // their value from the previous animation call.
+ if (!NeedsUpdate(monotonic_time, scroll_tree, is_active_tree))
+ return;
+
+ double current_time =
+ CurrentTime(monotonic_time, scroll_tree, is_active_tree);
+ last_current_time_ = current_time;
+
+ switch (state_) {
+ case State::PENDING:
+ input_state->Add(
+ {worklet_animation_id(), name(), current_time, CloneOptions()});
+ state_ = State::RUNNING;
+ break;
+ case State::RUNNING:
+ input_state->Update({worklet_animation_id(), current_time});
+ break;
+ case State::REMOVED:
+ input_state->Remove(worklet_animation_id());
+ break;
}
+}
+
+void WorkletAnimation::SetOutputState(
+ const MutatorOutputState::AnimationState& state) {
+ local_time_ = state.local_time;
+}
- // TODO(crbug.com/783333): Support DocumentTimeline's originTime concept.
- return (monotonic_time - base::TimeTicks()).InMillisecondsF();
+// TODO(crbug.com/780151): Multiply the result by the play back rate.
+double WorkletAnimation::CurrentTime(base::TimeTicks monotonic_time,
+ const ScrollTree& scroll_tree,
+ bool is_active_tree) {
+ // Note that we have intentionally decided not to offset the scroll timeline
+ // by the start time. See: https://github.com/w3c/csswg-drafts/issues/2075
+ if (scroll_timeline_)
+ return scroll_timeline_->CurrentTime(scroll_tree, is_active_tree);
+ return (monotonic_time - start_time_.value()).InMillisecondsF();
}
bool WorkletAnimation::NeedsUpdate(base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree) {
- double current_time = CurrentTime(monotonic_time, scroll_tree);
+ const ScrollTree& scroll_tree,
+ bool is_active_tree) {
+ // If we don't have a start time it means that an update was never sent to
+ // the worklet therefore we need one.
+ if (!scroll_timeline_ && !start_time_.has_value())
+ return true;
+
+ DCHECK(state_ == State::PENDING || last_current_time_.has_value());
+ if (state_ == State::REMOVED)
+ return true;
+
+ double current_time =
+ CurrentTime(monotonic_time, scroll_tree, is_active_tree);
bool needs_update = last_current_time_ != current_time;
- last_current_time_ = current_time;
return needs_update;
}
+void WorkletAnimation::SetScrollSourceId(
+ base::Optional<ElementId> scroller_id) {
+ // Calling this method implies that we are a ScrollTimeline based animation,
+ // so the below call is done unchecked.
+ scroll_timeline_->SetScrollerId(scroller_id);
+ SetNeedsPushProperties();
+}
+
+void WorkletAnimation::PromoteScrollTimelinePendingToActive() {
+ if (scroll_timeline_)
+ scroll_timeline_->PromoteScrollTimelinePendingToActive();
+}
+
+void WorkletAnimation::RemoveKeyframeModel(int keyframe_model_id) {
+ state_ = State::REMOVED;
+ SingleKeyframeEffectAnimation::RemoveKeyframeModel(keyframe_model_id);
+}
+
bool WorkletAnimation::IsWorkletAnimation() const {
return true;
}
diff --git a/chromium/cc/animation/worklet_animation.h b/chromium/cc/animation/worklet_animation.h
index cdde572fd28..1ab919d555e 100644
--- a/chromium/cc/animation/worklet_animation.h
+++ b/chromium/cc/animation/worklet_animation.h
@@ -5,14 +5,21 @@
#ifndef CC_ANIMATION_WORKLET_ANIMATION_H_
#define CC_ANIMATION_WORKLET_ANIMATION_H_
+#include "base/gtest_prod_util.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
-#include "cc/animation/keyframe_effect.h"
+#include "cc/animation/animation_host.h"
#include "cc/animation/single_keyframe_effect_animation.h"
+#include "cc/trees/property_tree.h"
namespace cc {
+namespace {
+FORWARD_DECLARE_TEST(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe);
+} // namespace
+
+class AnimationOptions;
class ScrollTimeline;
// A WorkletAnimation is an animation that allows its animation
@@ -21,39 +28,79 @@ class ScrollTimeline;
class CC_ANIMATION_EXPORT WorkletAnimation final
: public SingleKeyframeEffectAnimation {
public:
- WorkletAnimation(int id,
+ enum class State { PENDING, RUNNING, REMOVED };
+ WorkletAnimation(int cc_animation_id,
+ WorkletAnimationId worklet_animation_id,
const std::string& name,
std::unique_ptr<ScrollTimeline> scroll_timeline,
+ std::unique_ptr<AnimationOptions> options,
bool is_controlling_instance);
static scoped_refptr<WorkletAnimation> Create(
- int id,
+ WorkletAnimationId worklet_animation_id,
const std::string& name,
- std::unique_ptr<ScrollTimeline> scroll_timeline);
+ std::unique_ptr<ScrollTimeline> scroll_timeline,
+ std::unique_ptr<AnimationOptions> options);
scoped_refptr<Animation> CreateImplInstance() const override;
+ WorkletAnimationId worklet_animation_id() { return worklet_animation_id_; }
const std::string& name() const { return name_; }
const ScrollTimeline* scroll_timeline() const {
return scroll_timeline_.get();
}
- void SetLocalTime(base::TimeDelta local_time);
bool IsWorkletAnimation() const override;
void Tick(base::TimeTicks monotonic_time) override;
+ void UpdateInputState(MutatorInputState* input_state,
+ base::TimeTicks monotonic_time,
+ const ScrollTree& scroll_tree,
+ bool is_active_tree);
+ void SetOutputState(const MutatorOutputState::AnimationState& state);
+
+ void PushPropertiesTo(Animation* animation_impl) override;
+
+ // Should be called when the scroll source of the ScrollTimeline attached to
+ // this animation has a change in ElementId. Such a change happens when the
+ // scroll source changes compositing state.
+ void SetScrollSourceId(base::Optional<ElementId> scroller_id);
+
+ // Should be called when the pending tree is promoted to active, as this may
+ // require updating the ElementId for the ScrollTimeline scroll source.
+ void PromoteScrollTimelinePendingToActive() override;
+
+ void RemoveKeyframeModel(int keyframe_model_id) override;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(WorkletAnimationTest,
+ NonImplInstanceDoesNotTickKeyframe);
+ WorkletAnimation(int cc_animation_id,
+ WorkletAnimationId worklet_animation_id,
+ const std::string& name,
+ std::unique_ptr<ScrollTimeline> scroll_timeline,
+ std::unique_ptr<AnimationOptions> options,
+ bool is_controlling_instance,
+ std::unique_ptr<KeyframeEffect> effect);
+
+ ~WorkletAnimation() override;
+
// Returns the current time to be passed into the underlying AnimationWorklet.
// The current time is based on the timeline associated with the animation.
double CurrentTime(base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree);
+ const ScrollTree& scroll_tree,
+ bool is_active_tree);
// Returns true if the worklet animation needs to be updated which happens iff
// its current time is going to be different from last time given these input.
bool NeedsUpdate(base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree);
+ const ScrollTree& scroll_tree,
+ bool is_active_tree);
- private:
- ~WorkletAnimation() override;
+ std::unique_ptr<AnimationOptions> CloneOptions() const {
+ return options_ ? options_->Clone() : nullptr;
+ }
+ WorkletAnimationId worklet_animation_id_;
std::string name_;
// The ScrollTimeline associated with the underlying animation. If null, the
@@ -64,13 +111,28 @@ class CC_ANIMATION_EXPORT WorkletAnimation final
// some other future implementation.
std::unique_ptr<ScrollTimeline> scroll_timeline_;
- base::TimeDelta local_time_;
+ std::unique_ptr<AnimationOptions> options_;
+
+ // Local time is used as an input to the keyframe effect of this animation.
+ // The value comes from the user script that runs inside the animation worklet
+ // global scope.
+ base::Optional<base::TimeDelta> local_time_;
+ base::Optional<base::TimeTicks> start_time_;
+ // Last current time used for updatig. We use this to skip updating if current
+ // time has not changed since last update.
base::Optional<double> last_current_time_;
+ State state_;
+
bool is_impl_instance_;
};
+inline WorkletAnimation* ToWorkletAnimation(Animation* animation) {
+ DCHECK(animation->IsWorkletAnimation());
+ return static_cast<WorkletAnimation*>(animation);
+}
+
} // namespace cc
#endif // CC_ANIMATION_WORKLET_ANIMATION_H_
diff --git a/chromium/cc/animation/worklet_animation_unittest.cc b/chromium/cc/animation/worklet_animation_unittest.cc
index 5e3020b75e9..74ac4ab9925 100644
--- a/chromium/cc/animation/worklet_animation_unittest.cc
+++ b/chromium/cc/animation/worklet_animation_unittest.cc
@@ -13,6 +13,7 @@
#include "testing/gmock/include/gmock/gmock.h"
using ::testing::Mock;
+using ::testing::NiceMock;
using ::testing::Return;
using ::testing::_;
@@ -20,6 +21,12 @@ namespace cc {
namespace {
+class MockKeyframeEffect : public KeyframeEffect {
+ public:
+ MockKeyframeEffect() : KeyframeEffect(0) {}
+ MOCK_METHOD1(Tick, void(base::TimeTicks monotonic_time));
+};
+
class WorkletAnimationTest : public AnimationTimelinesTest {
public:
WorkletAnimationTest() = default;
@@ -30,31 +37,47 @@ class WorkletAnimationTest : public AnimationTimelinesTest {
client_impl_.RegisterElement(element_id_, ElementListType::PENDING);
client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE);
- worklet_animation_ =
- WorkletAnimation::Create(worklet_animation_id_, "test_name", nullptr);
-
+ worklet_animation_ = WorkletAnimation::Create(
+ worklet_animation_id_, "test_name", nullptr, nullptr);
+ int cc_id = worklet_animation_->id();
worklet_animation_->AttachElement(element_id_);
host_->AddAnimationTimeline(timeline_);
timeline_->AttachAnimation(worklet_animation_);
host_->PushPropertiesTo(host_impl_);
timeline_impl_ = host_impl_->GetTimelineById(timeline_id_);
- worklet_animation_impl_ = static_cast<WorkletAnimation*>(
- timeline_impl_->GetAnimationById(worklet_animation_id_));
+ worklet_animation_impl_ =
+ ToWorkletAnimation(timeline_impl_->GetAnimationById(cc_id));
}
scoped_refptr<WorkletAnimation> worklet_animation_;
scoped_refptr<WorkletAnimation> worklet_animation_impl_;
- int worklet_animation_id_ = 11;
+ WorkletAnimationId worklet_animation_id_{11, 12};
};
class MockScrollTimeline : public ScrollTimeline {
public:
MockScrollTimeline()
: ScrollTimeline(ElementId(), ScrollTimeline::Vertical, 0) {}
- MOCK_CONST_METHOD1(CurrentTime, double(const ScrollTree&));
+ MOCK_CONST_METHOD2(CurrentTime, double(const ScrollTree&, bool));
};
+TEST_F(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe) {
+ std::unique_ptr<MockKeyframeEffect> effect =
+ std::make_unique<MockKeyframeEffect>();
+ MockKeyframeEffect* mock_effect = effect.get();
+
+ scoped_refptr<WorkletAnimation> worklet_animation =
+ WrapRefCounted(new WorkletAnimation(
+ 1, worklet_animation_id_, "test_name", nullptr, nullptr,
+ false /* not impl instance*/, std::move(effect)));
+
+ EXPECT_CALL(*mock_effect, Tick(_)).Times(0);
+ worklet_animation->SetOutputState(
+ {worklet_animation_id_, base::TimeDelta::FromSecondsD(1)});
+ worklet_animation->Tick(base::TimeTicks());
+}
+
TEST_F(WorkletAnimationTest, LocalTimeIsUsedWithAnimations) {
AttachWorkletAnimation();
@@ -72,7 +95,7 @@ TEST_F(WorkletAnimationTest, LocalTimeIsUsedWithAnimations) {
host_impl_->ActivateAnimations();
base::TimeDelta local_time = base::TimeDelta::FromSecondsD(duration / 2);
- worklet_animation_impl_->SetLocalTime(local_time);
+ worklet_animation_impl_->SetOutputState({worklet_animation_id_, local_time});
TickAnimationsTransferEvents(base::TimeTicks(), 0u);
@@ -82,13 +105,12 @@ TEST_F(WorkletAnimationTest, LocalTimeIsUsedWithAnimations) {
client_impl_.ExpectOpacityPropertyMutated(
element_id_, ElementListType::ACTIVE, expected_opacity);
}
-
// Tests that verify interaction of AnimationHost with LayerTreeMutator.
// TODO(majidvp): Perhaps moves these to AnimationHostTest.
TEST_F(WorkletAnimationTest, LayerTreeMutatorsIsMutatedWithCorrectInputState) {
AttachWorkletAnimation();
- MockLayerTreeMutator* mock_mutator = new MockLayerTreeMutator();
+ MockLayerTreeMutator* mock_mutator = new NiceMock<MockLayerTreeMutator>();
host_impl_->SetLayerTreeMutator(
base::WrapUnique<LayerTreeMutator>(mock_mutator));
ON_CALL(*mock_mutator, HasAnimators()).WillByDefault(Return(true));
@@ -115,7 +137,7 @@ TEST_F(WorkletAnimationTest, LayerTreeMutatorsIsMutatedWithCorrectInputState) {
TEST_F(WorkletAnimationTest, LayerTreeMutatorsIsMutatedOnlyWhenInputChanges) {
AttachWorkletAnimation();
- MockLayerTreeMutator* mock_mutator = new MockLayerTreeMutator();
+ MockLayerTreeMutator* mock_mutator = new NiceMock<MockLayerTreeMutator>();
host_impl_->SetLayerTreeMutator(
base::WrapUnique<LayerTreeMutator>(mock_mutator));
ON_CALL(*mock_mutator, HasAnimators()).WillByDefault(Return(true));
@@ -144,15 +166,187 @@ TEST_F(WorkletAnimationTest, LayerTreeMutatorsIsMutatedOnlyWhenInputChanges) {
Mock::VerifyAndClearExpectations(mock_mutator);
}
-TEST_F(WorkletAnimationTest, CurrentTimeCorrectlyUsesScrolltimeline) {
+TEST_F(WorkletAnimationTest, CurrentTimeCorrectlyUsesScrollTimeline) {
auto scroll_timeline = std::make_unique<MockScrollTimeline>();
- EXPECT_CALL(*scroll_timeline, CurrentTime(_)).WillOnce(Return(1234));
+ EXPECT_CALL(*scroll_timeline, CurrentTime(_, _)).WillRepeatedly(Return(1234));
scoped_refptr<WorkletAnimation> worklet_animation = WorkletAnimation::Create(
- worklet_animation_id_, "test_name", std::move(scroll_timeline));
+ worklet_animation_id_, "test_name", std::move(scroll_timeline), nullptr);
+
+ ScrollTree scroll_tree;
+ std::unique_ptr<MutatorInputState> state =
+ std::make_unique<MutatorInputState>();
+ worklet_animation->UpdateInputState(state.get(), base::TimeTicks::Now(),
+ scroll_tree, true);
+ std::unique_ptr<AnimationWorkletInput> input =
+ state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(1234, input->added_and_updated_animations[0].current_time);
+}
+
+TEST_F(WorkletAnimationTest,
+ CurrentTimeFromDocumentTimelineIsOffsetByStartTime) {
+ scoped_refptr<WorkletAnimation> worklet_animation = WorkletAnimation::Create(
+ worklet_animation_id_, "test_name", nullptr, nullptr);
+
+ base::TimeTicks first_ticks =
+ base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111);
+ base::TimeTicks second_ticks =
+ base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111 + 123.4);
+ base::TimeTicks third_ticks =
+ base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111 + 246.8);
+
+ ScrollTree scroll_tree;
+ std::unique_ptr<MutatorInputState> state =
+ std::make_unique<MutatorInputState>();
+ worklet_animation->UpdateInputState(state.get(), first_ticks, scroll_tree,
+ true);
+ // First state request sets the start time and thus current time should be 0.
+ std::unique_ptr<AnimationWorkletInput> input =
+ state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(0, input->added_and_updated_animations[0].current_time);
+ state.reset(new MutatorInputState);
+ worklet_animation->UpdateInputState(state.get(), second_ticks, scroll_tree,
+ true);
+ input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(123.4, input->updated_animations[0].current_time);
+ // Should always offset from start time.
+ state.reset(new MutatorInputState());
+ worklet_animation->UpdateInputState(state.get(), third_ticks, scroll_tree,
+ true);
+ input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(246.8, input->updated_animations[0].current_time);
+}
+
+// This test verifies that worklet animation state is properly updated.
+TEST_F(WorkletAnimationTest, WorkletAnimationStateTestWithSingleKeyframeModel) {
+ AttachWorkletAnimation();
+
+ MockLayerTreeMutator* mock_mutator = new NiceMock<MockLayerTreeMutator>();
+ host_impl_->SetLayerTreeMutator(
+ base::WrapUnique<LayerTreeMutator>(mock_mutator));
+ ON_CALL(*mock_mutator, HasAnimators()).WillByDefault(Return(true));
+
+ const float start_opacity = .7f;
+ const float end_opacity = .3f;
+ const double duration = 1.;
+
+ int keyframe_model_id = AddOpacityTransitionToAnimation(
+ worklet_animation_.get(), duration, start_opacity, end_opacity, true);
ScrollTree scroll_tree;
- EXPECT_EQ(1234, worklet_animation->CurrentTime(base::TimeTicks::Now(),
- scroll_tree));
+ std::unique_ptr<MutatorEvents> events = host_->CreateEvents();
+ std::unique_ptr<MutatorInputState> state =
+ std::make_unique<MutatorInputState>();
+
+ host_->PushPropertiesTo(host_impl_);
+ host_impl_->ActivateAnimations();
+
+ KeyframeModel* keyframe_model =
+ worklet_animation_impl_->GetKeyframeModel(TargetProperty::OPACITY);
+ ASSERT_TRUE(keyframe_model);
+
+ base::TimeTicks time;
+ worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
+ true);
+ std::unique_ptr<AnimationWorkletInput> input =
+ state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(input->added_and_updated_animations.size(), 1u);
+ EXPECT_EQ("test_name", input->added_and_updated_animations[0].name);
+ EXPECT_EQ(input->updated_animations.size(), 0u);
+ EXPECT_EQ(input->removed_animations.size(), 0u);
+
+ // The state of WorkletAnimation is updated to RUNNING after calling
+ // UpdateInputState above.
+ state.reset(new MutatorInputState());
+ time += base::TimeDelta::FromSecondsD(0.1);
+ worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
+ true);
+ input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
+ EXPECT_EQ(input->updated_animations.size(), 1u);
+ EXPECT_EQ(input->removed_animations.size(), 0u);
+
+ // Operating on individual KeyframeModel doesn't affect the state of
+ // WorkletAnimation.
+ keyframe_model->SetRunState(KeyframeModel::FINISHED, time);
+ state.reset(new MutatorInputState());
+ time += base::TimeDelta::FromSecondsD(0.1);
+ worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
+ true);
+ input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
+ EXPECT_EQ(input->updated_animations.size(), 1u);
+ EXPECT_EQ(input->removed_animations.size(), 0u);
+
+ // WorkletAnimation sets state to REMOVED when JavaScript fires cancel() which
+ // leads to RemoveKeyframeModel.
+ worklet_animation_impl_->RemoveKeyframeModel(keyframe_model_id);
+ host_impl_->UpdateAnimationState(true, events.get());
+ state.reset(new MutatorInputState());
+ worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
+ true);
+ input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
+ EXPECT_EQ(input->updated_animations.size(), 0u);
+ EXPECT_EQ(input->removed_animations.size(), 1u);
+ EXPECT_EQ(input->removed_animations[0], worklet_animation_id_);
+}
+
+// This test verifies that worklet animation gets skipped properly.
+TEST_F(WorkletAnimationTest, SkipUnchangedAnimations) {
+ AttachWorkletAnimation();
+
+ MockLayerTreeMutator* mock_mutator = new NiceMock<MockLayerTreeMutator>();
+ host_impl_->SetLayerTreeMutator(
+ base::WrapUnique<LayerTreeMutator>(mock_mutator));
+ ON_CALL(*mock_mutator, HasAnimators()).WillByDefault(Return(true));
+
+ const float start_opacity = .7f;
+ const float end_opacity = .3f;
+ const double duration = 1.;
+
+ int keyframe_model_id = AddOpacityTransitionToAnimation(
+ worklet_animation_.get(), duration, start_opacity, end_opacity, true);
+
+ ScrollTree scroll_tree;
+ std::unique_ptr<MutatorEvents> events = host_->CreateEvents();
+ std::unique_ptr<MutatorInputState> state =
+ std::make_unique<MutatorInputState>();
+
+ host_->PushPropertiesTo(host_impl_);
+ host_impl_->ActivateAnimations();
+
+ base::TimeTicks time;
+ worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
+ true);
+ std::unique_ptr<AnimationWorkletInput> input =
+ state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(input->added_and_updated_animations.size(), 1u);
+ EXPECT_EQ(input->updated_animations.size(), 0u);
+
+ state.reset(new MutatorInputState());
+ // No update on the input state if input time stays the same.
+ worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
+ true);
+ input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_FALSE(input);
+
+ state.reset(new MutatorInputState());
+ // Different input time causes the input state to be updated.
+ time += base::TimeDelta::FromSecondsD(0.1);
+ worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
+ true);
+ input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(input->updated_animations.size(), 1u);
+
+ state.reset(new MutatorInputState());
+ // Input state gets updated when the worklet animation is to be removed even
+ // the input time doesn't change.
+ worklet_animation_impl_->RemoveKeyframeModel(keyframe_model_id);
+ worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
+ true);
+ input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+ EXPECT_EQ(input->updated_animations.size(), 0u);
+ EXPECT_EQ(input->removed_animations.size(), 1u);
}
} // namespace
diff --git a/chromium/cc/base/list_container.h b/chromium/cc/base/list_container.h
index 81235e1bc0a..ac7b820fffd 100644
--- a/chromium/cc/base/list_container.h
+++ b/chromium/cc/base/list_container.h
@@ -136,6 +136,16 @@ class ListContainer {
return result;
}
+ // Insert |count| new elements of |DerivedElementType| after |at|. If |at| is
+ // end() elements will be inserted to the empty list. This will invalidate all
+ // outstanding pointers and iterators. Return a valid iterator for the
+ // beginning of the newly inserted segment.
+ template <typename DerivedElementType>
+ Iterator InsertAfterAndInvalidateAllPointers(Iterator at, size_t count) {
+ return InsertBeforeAndInvalidateAllPointers<DerivedElementType>(
+ at != end() ? ++at : at, count);
+ }
+
ListContainer& operator=(ListContainer&& other) {
helper_.data_.swap(other.helper_.data_);
return *this;
diff --git a/chromium/cc/base/list_container_unittest.cc b/chromium/cc/base/list_container_unittest.cc
index e46be3bf875..c58597b2abd 100644
--- a/chromium/cc/base/list_container_unittest.cc
+++ b/chromium/cc/base/list_container_unittest.cc
@@ -8,6 +8,8 @@
#include <algorithm>
#include <vector>
+
+#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
@@ -714,18 +716,17 @@ TEST(ListContainerTest, DeletionWhileIterating) {
TEST(ListContainerTest, InsertBeforeBegin) {
ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
kCurrentLargestDerivedElementSize, 0);
- std::vector<SimpleDerivedElement*> sde_list;
const int size = 4;
for (int i = 0; i < size; ++i) {
- sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
- sde_list.back()->set_value(i);
+ SimpleDerivedElement* element =
+ list.AllocateAndConstruct<SimpleDerivedElement>();
+ element->set_value(i);
}
EXPECT_EQ(static_cast<size_t>(size), list.size());
const int count = 2;
- ListContainer<DerivedElement>::Iterator iter =
- list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>(
- list.begin(), count);
+ auto iter = list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>(
+ list.begin(), count);
for (int i = 0; i < count; ++i) {
static_cast<SimpleDerivedElement*>(*iter)->set_value(100 + i);
++iter;
@@ -744,18 +745,17 @@ TEST(ListContainerTest, InsertBeforeBegin) {
TEST(ListContainerTest, InsertBeforeEnd) {
ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
kCurrentLargestDerivedElementSize, 0);
- std::vector<SimpleDerivedElement*> sde_list;
const int size = 4;
for (int i = 0; i < size; ++i) {
- sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
- sde_list.back()->set_value(i);
+ SimpleDerivedElement* element =
+ list.AllocateAndConstruct<SimpleDerivedElement>();
+ element->set_value(i);
}
EXPECT_EQ(static_cast<size_t>(size), list.size());
const int count = 3;
- ListContainer<DerivedElement>::Iterator iter =
- list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>(
- list.end(), count);
+ auto iter = list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>(
+ list.end(), count);
for (int i = 0; i < count; ++i) {
static_cast<SimpleDerivedElement*>(*iter)->set_value(100 + i);
++iter;
@@ -776,9 +776,8 @@ TEST(ListContainerTest, InsertBeforeEmpty) {
kCurrentLargestDerivedElementSize, 0);
const int count = 3;
- ListContainer<DerivedElement>::Iterator iter =
- list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>(
- list.end(), count);
+ auto iter = list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>(
+ list.end(), count);
for (int i = 0; i < count; ++i) {
static_cast<SimpleDerivedElement*>(*iter)->set_value(100 + i);
++iter;
@@ -797,24 +796,24 @@ TEST(ListContainerTest, InsertBeforeEmpty) {
TEST(ListContainerTest, InsertBeforeMany) {
ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
kCurrentLargestDerivedElementSize, 0);
- std::vector<SimpleDerivedElement*> sde_list;
// Create a partial list of 1,...,99.
int initial_list[] = {
0, 1, 4, 5, 6, 7, 8, 9, 11, 12, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 36, 37, 51, 52, 54, 56,
60, 64, 65, 70, 75, 76, 80, 81, 83, 86, 87, 90, 93, 95, 97, 98,
};
- const size_t size = sizeof(initial_list) / sizeof(initial_list[0]);
+ const size_t size = base::size(initial_list);
for (size_t i = 0; i < size; ++i) {
- sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
- sde_list.back()->set_value(initial_list[i]);
+ SimpleDerivedElement* element =
+ list.AllocateAndConstruct<SimpleDerivedElement>();
+ element->set_value(initial_list[i]);
}
EXPECT_EQ(static_cast<size_t>(size), list.size());
// Insert the missing elements.
- ListContainer<DerivedElement>::Iterator iter = list.begin();
+ auto iter = list.begin();
while (iter != list.end()) {
- ListContainer<DerivedElement>::Iterator iter_next = iter;
+ auto iter_next = iter;
++iter_next;
int value = static_cast<SimpleDerivedElement*>(*iter)->get_value();
@@ -841,6 +840,133 @@ TEST(ListContainerTest, InsertBeforeMany) {
EXPECT_EQ(100, iter_index);
}
+TEST(ListContainerTest, InsertAfterBegin) {
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
+ const int size = 4;
+ for (int i = 0; i < size; ++i) {
+ SimpleDerivedElement* element =
+ list.AllocateAndConstruct<SimpleDerivedElement>();
+ element->set_value(i);
+ }
+ EXPECT_EQ(static_cast<size_t>(size), list.size());
+
+ const int count = 2;
+ auto iter = list.InsertAfterAndInvalidateAllPointers<SimpleDerivedElement>(
+ list.begin(), count);
+ for (int i = 0; i < count; ++i) {
+ static_cast<SimpleDerivedElement*>(*iter)->set_value(100 + i);
+ ++iter;
+ }
+
+ const int expected_result[] = {0, 100, 101, 1, 2, 3};
+ int iter_index = 0;
+ for (iter = list.begin(); iter != list.end(); ++iter) {
+ EXPECT_EQ(expected_result[iter_index],
+ static_cast<SimpleDerivedElement*>(*iter)->get_value());
+ ++iter_index;
+ }
+ EXPECT_EQ(size + count, iter_index);
+}
+
+TEST(ListContainerTest, InsertAfterEnd) {
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
+ const int size = 4;
+ for (int i = 0; i < size; ++i) {
+ SimpleDerivedElement* element =
+ list.AllocateAndConstruct<SimpleDerivedElement>();
+ element->set_value(i);
+ }
+ EXPECT_EQ(static_cast<size_t>(size), list.size());
+
+ const int count = 3;
+ auto iter = list.InsertAfterAndInvalidateAllPointers<SimpleDerivedElement>(
+ list.end(), count);
+ for (int i = 0; i < count; ++i) {
+ static_cast<SimpleDerivedElement*>(*iter)->set_value(100 + i);
+ ++iter;
+ }
+
+ const int expected_result[] = {0, 1, 2, 3, 100, 101, 102};
+ int iter_index = 0;
+ for (iter = list.begin(); iter != list.end(); ++iter) {
+ EXPECT_EQ(expected_result[iter_index],
+ static_cast<SimpleDerivedElement*>(*iter)->get_value());
+ ++iter_index;
+ }
+ EXPECT_EQ(size + count, iter_index);
+}
+
+TEST(ListContainerTest, InsertAfterEmpty) {
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
+
+ const int count = 3;
+ auto iter = list.InsertAfterAndInvalidateAllPointers<SimpleDerivedElement>(
+ list.end(), count);
+ for (int i = 0; i < count; ++i) {
+ static_cast<SimpleDerivedElement*>(*iter)->set_value(100 + i);
+ ++iter;
+ }
+
+ const int expected_result[] = {100, 101, 102};
+ int iter_index = 0;
+ for (iter = list.begin(); iter != list.end(); ++iter) {
+ EXPECT_EQ(expected_result[iter_index],
+ static_cast<SimpleDerivedElement*>(*iter)->get_value());
+ ++iter_index;
+ }
+ EXPECT_EQ(count, iter_index);
+}
+
+TEST(ListContainerTest, InsertAfterMany) {
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
+ // Create a partial list of 1,...,99.
+ int initial_list[] = {
+ 0, 1, 4, 5, 6, 7, 8, 9, 11, 12, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 36, 37, 51, 52, 54, 56,
+ 60, 64, 65, 70, 75, 76, 80, 81, 83, 86, 87, 90, 93, 95, 97, 98,
+ };
+ const size_t size = base::size(initial_list);
+ for (size_t i = 0; i < size; ++i) {
+ SimpleDerivedElement* element =
+ list.AllocateAndConstruct<SimpleDerivedElement>();
+ element->set_value(initial_list[i]);
+ }
+ EXPECT_EQ(static_cast<size_t>(size), list.size());
+
+ // Insert the missing elements.
+ auto iter = list.begin();
+ while (iter != list.end()) {
+ auto iter_next = iter;
+ ++iter_next;
+
+ int value = static_cast<SimpleDerivedElement*>(*iter)->get_value();
+ int value_next =
+ iter_next != list.end()
+ ? static_cast<SimpleDerivedElement*>(*iter_next)->get_value()
+ : 100;
+ int count = value_next - value - 1;
+
+ iter = list.InsertAfterAndInvalidateAllPointers<SimpleDerivedElement>(
+ iter, count);
+ for (int i = value + 1; i < value_next; ++i) {
+ static_cast<SimpleDerivedElement*>(*iter)->set_value(i);
+ ++iter;
+ }
+ }
+
+ int iter_index = 0;
+ for (iter = list.begin(); iter != list.end(); ++iter) {
+ EXPECT_EQ(iter_index,
+ static_cast<SimpleDerivedElement*>(*iter)->get_value());
+ ++iter_index;
+ }
+ EXPECT_EQ(100, iter_index);
+}
+
TEST(ListContainerTest, SimpleManipulationWithIndexSimpleDerivedElement) {
ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
kCurrentLargestDerivedElementSize, 0);
diff --git a/chromium/cc/benchmarks/micro_benchmark.cc b/chromium/cc/benchmarks/micro_benchmark.cc
index 448c62dfdc5..5f23e66ee37 100644
--- a/chromium/cc/benchmarks/micro_benchmark.cc
+++ b/chromium/cc/benchmarks/micro_benchmark.cc
@@ -34,8 +34,6 @@ void MicroBenchmark::NotifyDone(std::unique_ptr<base::Value> result) {
is_done_ = true;
}
-void MicroBenchmark::RunOnLayer(Layer* layer) {}
-
void MicroBenchmark::RunOnLayer(PictureLayer* layer) {}
bool MicroBenchmark::ProcessMessage(std::unique_ptr<base::Value> value) {
diff --git a/chromium/cc/benchmarks/micro_benchmark.h b/chromium/cc/benchmarks/micro_benchmark.h
index 918e78d4a30..913956440bf 100644
--- a/chromium/cc/benchmarks/micro_benchmark.h
+++ b/chromium/cc/benchmarks/micro_benchmark.h
@@ -16,11 +16,10 @@ class Value;
} // namespace base
namespace cc {
-
-class Layer;
class LayerTreeHost;
class PictureLayer;
class MicroBenchmarkImpl;
+
class CC_EXPORT MicroBenchmark {
public:
using DoneCallback = base::OnceCallback<void(std::unique_ptr<base::Value>)>;
@@ -33,7 +32,6 @@ class CC_EXPORT MicroBenchmark {
int id() const { return id_; }
void set_id(int id) { id_ = id; }
- virtual void RunOnLayer(Layer* layer);
virtual void RunOnLayer(PictureLayer* layer);
virtual bool ProcessMessage(std::unique_ptr<base::Value> value);
diff --git a/chromium/cc/input/browser_controls_offset_manager.cc b/chromium/cc/input/browser_controls_offset_manager.cc
index 33ce93fc98d..e55bf940440 100644
--- a/chromium/cc/input/browser_controls_offset_manager.cc
+++ b/chromium/cc/input/browser_controls_offset_manager.cc
@@ -41,7 +41,7 @@ BrowserControlsOffsetManager::BrowserControlsOffsetManager(
animation_start_value_(0.f),
animation_stop_value_(0.f),
animation_direction_(NO_ANIMATION),
- permitted_state_(BOTH),
+ permitted_state_(BrowserControlsState::kBoth),
accumulated_scroll_delta_(0.f),
baseline_top_content_offset_(0.f),
baseline_bottom_content_offset_(0.f),
@@ -87,18 +87,22 @@ void BrowserControlsOffsetManager::UpdateBrowserControlsState(
BrowserControlsState constraints,
BrowserControlsState current,
bool animate) {
- DCHECK(!(constraints == SHOWN && current == HIDDEN));
- DCHECK(!(constraints == HIDDEN && current == SHOWN));
+ DCHECK(!(constraints == BrowserControlsState::kShown &&
+ current == BrowserControlsState::kHidden));
+ DCHECK(!(constraints == BrowserControlsState::kHidden &&
+ current == BrowserControlsState::kShown));
permitted_state_ = constraints;
// Don't do anything if it doesn't matter which state the controls are in.
- if (constraints == BOTH && current == BOTH)
+ if (constraints == BrowserControlsState::kBoth &&
+ current == BrowserControlsState::kBoth)
return;
// Don't do anything if there is no change in offset.
float final_shown_ratio = 1.f;
- if (constraints == HIDDEN || current == HIDDEN)
+ if (constraints == BrowserControlsState::kHidden ||
+ current == BrowserControlsState::kHidden)
final_shown_ratio = 0.f;
if (final_shown_ratio == TopControlsShownRatio()) {
ResetAnimations();
@@ -134,9 +138,10 @@ gfx::Vector2dF BrowserControlsOffsetManager::ScrollBy(
if (pinch_gesture_active_)
return pending_delta;
- if (permitted_state_ == SHOWN && pending_delta.y() > 0)
+ if (permitted_state_ == BrowserControlsState::kShown && pending_delta.y() > 0)
return pending_delta;
- else if (permitted_state_ == HIDDEN && pending_delta.y() < 0)
+ else if (permitted_state_ == BrowserControlsState::kHidden &&
+ pending_delta.y() < 0)
return pending_delta;
accumulated_scroll_delta_ += pending_delta.y();
@@ -189,7 +194,7 @@ void BrowserControlsOffsetManager::MainThreadHasStoppedFlinging() {
gfx::Vector2dF BrowserControlsOffsetManager::Animate(
base::TimeTicks monotonic_time) {
- if (!has_animation() || !client_->HaveRootScrollLayer())
+ if (!has_animation() || !client_->HaveRootScrollNode())
return gfx::Vector2dF();
float old_offset = ContentTopOffset();
diff --git a/chromium/cc/input/browser_controls_offset_manager_client.h b/chromium/cc/input/browser_controls_offset_manager_client.h
index 12e68aa3ae8..df1a742669d 100644
--- a/chromium/cc/input/browser_controls_offset_manager_client.h
+++ b/chromium/cc/input/browser_controls_offset_manager_client.h
@@ -14,7 +14,7 @@ class CC_EXPORT BrowserControlsOffsetManagerClient {
virtual void SetCurrentBrowserControlsShownRatio(float ratio) = 0;
virtual float CurrentBrowserControlsShownRatio() const = 0;
virtual void DidChangeBrowserControlsPosition() = 0;
- virtual bool HaveRootScrollLayer() const = 0;
+ virtual bool HaveRootScrollNode() const = 0;
protected:
virtual ~BrowserControlsOffsetManagerClient() {}
diff --git a/chromium/cc/input/browser_controls_offset_manager_unittest.cc b/chromium/cc/input/browser_controls_offset_manager_unittest.cc
index 098a701ece5..3caad9cd2ec 100644
--- a/chromium/cc/input/browser_controls_offset_manager_unittest.cc
+++ b/chromium/cc/input/browser_controls_offset_manager_unittest.cc
@@ -50,7 +50,7 @@ class MockBrowserControlsOffsetManagerClient
update_draw_properties_needed_ = true;
}
- bool HaveRootScrollLayer() const override { return true; }
+ bool HaveRootScrollNode() const override { return true; }
float BottomControlsHeight() const override {
return bottom_controls_height_;
@@ -509,7 +509,8 @@ TEST(BrowserControlsOffsetManagerTest,
TEST(BrowserControlsOffsetManagerTest, ScrollByWithZeroHeightControlsIsNoop) {
MockBrowserControlsOffsetManagerClient client(0.f, 0.5f, 0.5f);
BrowserControlsOffsetManager* manager = client.manager();
- manager->UpdateBrowserControlsState(BOTH, BOTH, false);
+ manager->UpdateBrowserControlsState(BrowserControlsState::kBoth,
+ BrowserControlsState::kBoth, false);
manager->ScrollBegin();
gfx::Vector2dF pending = manager->ScrollBy(gfx::Vector2dF(0.f, 20.f));
@@ -579,11 +580,13 @@ TEST(BrowserControlsOffsetManagerTest,
BrowserControlsOffsetManager* manager = client.manager();
EXPECT_FLOAT_EQ(1.f, client.CurrentBrowserControlsShownRatio());
- manager->UpdateBrowserControlsState(BOTH, HIDDEN, true);
+ manager->UpdateBrowserControlsState(BrowserControlsState::kBoth,
+ BrowserControlsState::kHidden, true);
EXPECT_TRUE(manager->has_animation());
EXPECT_FLOAT_EQ(1.f, client.CurrentBrowserControlsShownRatio());
- manager->UpdateBrowserControlsState(BOTH, SHOWN, true);
+ manager->UpdateBrowserControlsState(BrowserControlsState::kBoth,
+ BrowserControlsState::kShown, true);
EXPECT_FALSE(manager->has_animation());
EXPECT_FLOAT_EQ(1.f, client.CurrentBrowserControlsShownRatio());
}
diff --git a/chromium/cc/input/browser_controls_state.h b/chromium/cc/input/browser_controls_state.h
index 2d9208d883f..38310496c5a 100644
--- a/chromium/cc/input/browser_controls_state.h
+++ b/chromium/cc/input/browser_controls_state.h
@@ -6,11 +6,8 @@
#define CC_INPUT_BROWSER_CONTROLS_STATE_H_
namespace cc {
-enum BrowserControlsState {
- SHOWN = 1,
- HIDDEN = 2,
- BOTH = 3
-};
+
+enum class BrowserControlsState { kShown = 1, kHidden = 2, kBoth = 3 };
}
#endif // CC_INPUT_BROWSER_CONTROLS_STATE_H_
diff --git a/chromium/cc/input/event_listener_properties.h b/chromium/cc/input/event_listener_properties.h
index e1932afe2a9..dce12538e09 100644
--- a/chromium/cc/input/event_listener_properties.h
+++ b/chromium/cc/input/event_listener_properties.h
@@ -14,7 +14,7 @@ enum class EventListenerClass {
kMouseWheel,
// This value includes "touchend" and "touchcancel" events.
kTouchEndOrCancel,
- kNumClasses
+ kLast = kTouchEndOrCancel
};
enum class EventListenerProperties {
@@ -22,7 +22,7 @@ enum class EventListenerProperties {
kPassive,
kBlocking,
kBlockingAndPassive,
- kMax
+ kLast = kBlockingAndPassive
};
} // namespace cc
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index 51bc8f74b94..a35306042a3 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -62,7 +62,6 @@ class CC_EXPORT InputHandlerClient {
virtual void WillShutdown() = 0;
virtual void Animate(base::TimeTicks time) = 0;
- virtual void MainThreadHasStoppedFlinging() = 0;
virtual void ReconcileElasticOverscrollAndRootScroll() = 0;
virtual void UpdateRootLayerStateForSynchronousInputHandler(
const gfx::ScrollOffset& total_scroll_offset,
@@ -113,7 +112,6 @@ class CC_EXPORT InputHandler {
enum ScrollInputType {
TOUCHSCREEN,
WHEEL,
- NON_BUBBLING_GESTURE
};
enum class TouchStartOrMoveEventListenerType {
@@ -125,8 +123,7 @@ class CC_EXPORT InputHandler {
// Binds a client to this handler to receive notifications. Only one client
// can be bound to an InputHandler. The client must live at least until the
// handler calls WillShutdown() on the client.
- virtual void BindToClient(InputHandlerClient* client,
- bool wheel_scroll_latching_enabled) = 0;
+ virtual void BindToClient(InputHandlerClient* client) = 0;
// Selects a layer to be scrolled using the |scroll_state| start position.
// Returns SCROLL_STARTED if the layer at the coordinates can be scrolled,
@@ -165,10 +162,6 @@ class CC_EXPORT InputHandler {
// ScrollBegin() returned SCROLL_STARTED.
virtual InputHandlerScrollResult ScrollBy(ScrollState* scroll_state) = 0;
- // Returns SCROLL_STARTED if a layer was actively being scrolled,
- // SCROLL_IGNORED if not.
- virtual ScrollStatus FlingScrollBegin() = 0;
-
virtual void MouseMoveAt(const gfx::Point& mouse_position) = 0;
virtual void MouseDown() = 0;
virtual void MouseUp() = 0;
@@ -205,6 +198,11 @@ class CC_EXPORT InputHandler {
virtual EventListenerProperties GetEventListenerProperties(
EventListenerClass event_class) const = 0;
+ // Returns true if |viewport_point| hits a wheel event handler region that
+ // could block scrolling.
+ virtual bool HasWheelEventHandlerAt(
+ const gfx::Point& viewport_point) const = 0;
+
// It returns the type of a touch start or move event listener at
// |viewport_point|. Whether the page should be given the opportunity to
// suppress scrolling by consuming touch events that started at
diff --git a/chromium/cc/input/scroll_elasticity_helper.cc b/chromium/cc/input/scroll_elasticity_helper.cc
index 11d1393399d..1394e8ad6fc 100644
--- a/chromium/cc/input/scroll_elasticity_helper.cc
+++ b/chromium/cc/input/scroll_elasticity_helper.cc
@@ -67,11 +67,14 @@ gfx::ScrollOffset ScrollElasticityHelperImpl::MaxScrollOffset() const {
}
void ScrollElasticityHelperImpl::ScrollBy(const gfx::Vector2dF& delta) {
- LayerImpl* root_scroll_layer = host_impl_->OuterViewportScrollLayer()
- ? host_impl_->OuterViewportScrollLayer()
- : host_impl_->InnerViewportScrollLayer();
- if (root_scroll_layer)
- root_scroll_layer->ScrollBy(delta);
+ ScrollNode* root_scroll_node = host_impl_->OuterViewportScrollNode()
+ ? host_impl_->OuterViewportScrollNode()
+ : host_impl_->InnerViewportScrollNode();
+ if (root_scroll_node) {
+ LayerTreeImpl* tree_impl = host_impl_->active_tree();
+ tree_impl->property_trees()->scroll_tree.ScrollBy(root_scroll_node, delta,
+ tree_impl);
+ }
}
void ScrollElasticityHelperImpl::RequestOneBeginFrame() {
diff --git a/chromium/cc/input/scroll_snap_data.cc b/chromium/cc/input/scroll_snap_data.cc
index 58b225849d4..9e873aea523 100644
--- a/chromium/cc/input/scroll_snap_data.cc
+++ b/chromium/cc/input/scroll_snap_data.cc
@@ -4,81 +4,54 @@
#include "cc/input/scroll_snap_data.h"
+#include <algorithm>
#include <cmath>
-#include "base/optional.h"
namespace cc {
namespace {
-bool IsVisible(const gfx::ScrollOffset& point,
- const gfx::RectF& visible_region) {
- return point.x() >= visible_region.x() &&
- point.x() <= visible_region.right() &&
- point.y() >= visible_region.y() &&
- point.y() <= visible_region.bottom();
+bool IsMutualVisible(const SnapSearchResult& a, const SnapSearchResult& b) {
+ return a.visible_range().Contains(b.snap_offset()) &&
+ b.visible_range().Contains(a.snap_offset());
}
-bool IsMutualVisible(const SnapAreaData& area_x, const SnapAreaData& area_y) {
- gfx::ScrollOffset position(area_x.snap_position.x(),
- area_y.snap_position.y());
- return IsVisible(position, area_x.visible_region) &&
- IsVisible(position, area_y.visible_region);
+bool SnappableOnAxis(const SnapAreaData& area, SearchAxis search_axis) {
+ return search_axis == SearchAxis::kX
+ ? area.scroll_snap_align.alignment_inline != SnapAlignment::kNone
+ : area.scroll_snap_align.alignment_block != SnapAlignment::kNone;
}
-bool SnappableOnAxis(const SnapAreaData& area, SearchAxis search_axis) {
- return search_axis == SearchAxis::kX ? area.snap_axis == SnapAxis::kX ||
- area.snap_axis == SnapAxis::kBoth
- : area.snap_axis == SnapAxis::kY ||
- area.snap_axis == SnapAxis::kBoth;
+} // namespace
+
+bool SnapVisibleRange::Contains(float value) const {
+ if (start_ < end_)
+ return start_ <= value && value <= end_;
+ return end_ <= value && value <= start_;
}
-// Finds the best SnapArea candidate that minimizes the distance between current
-// and candidate positions, while satisfying three invariants:
-// - |candidate_position| is in |target_region|
-// - |current_position| is in candidate's visible region
-// - |target_position| is in candidate's visible region
-
-// |current_position| is the scroll position of the container before snapping.
-// |target_position| is the snap position we have found on the other axis.
-// |target_region| is the visible region of the target position's area.
-base::Optional<SnapAreaData> FindClosestValidArea(
- SearchAxis search_axis,
- const gfx::ScrollOffset& current_position,
- const gfx::ScrollOffset& target_position,
- const gfx::RectF& target_region,
- const gfx::ScrollOffset& proximity_range,
- const SnapAreaList& list) {
- if (list.empty())
- return base::nullopt;
-
- base::Optional<SnapAreaData> closest_area;
- float smallest_distance =
- search_axis == SearchAxis::kX ? proximity_range.x() : proximity_range.y();
- for (const SnapAreaData& area : list) {
- if (!SnappableOnAxis(area, search_axis))
- continue;
+SnapSearchResult::SnapSearchResult(float offset, const SnapVisibleRange& range)
+ : snap_offset_(offset) {
+ set_visible_range(range);
+}
- gfx::ScrollOffset candidate_position =
- search_axis == SearchAxis::kX
- ? gfx::ScrollOffset(area.snap_position.x(), target_position.y())
- : gfx::ScrollOffset(target_position.x(), area.snap_position.y());
- if (!IsVisible(candidate_position, target_region) ||
- !IsVisible(current_position, area.visible_region) ||
- !IsVisible(target_position, area.visible_region))
- continue;
+void SnapSearchResult::set_visible_range(const SnapVisibleRange& range) {
+ DCHECK(range.start() <= range.end());
+ visible_range_ = range;
+}
- gfx::ScrollOffset offset = current_position - candidate_position;
- float distance = search_axis == SearchAxis::kX ? std::abs(offset.x())
- : std::abs(offset.y());
- if (distance < smallest_distance) {
- smallest_distance = distance;
- closest_area = area;
- }
- }
- return closest_area;
+void SnapSearchResult::Clip(float max_snap, float max_visible) {
+ snap_offset_ = std::max(std::min(snap_offset_, max_snap), 0.0f);
+ visible_range_ = SnapVisibleRange(
+ std::max(std::min(visible_range_.start(), max_visible), 0.0f),
+ std::max(std::min(visible_range_.end(), max_visible), 0.0f));
}
-} // namespace
+void SnapSearchResult::Union(const SnapSearchResult& other) {
+ DCHECK(snap_offset_ == other.snap_offset_);
+ visible_range_ = SnapVisibleRange(
+ std::min(visible_range_.start(), other.visible_range_.start()),
+ std::max(visible_range_.end(), other.visible_range_.end()));
+}
SnapContainerData::SnapContainerData()
: proximity_range_(gfx::ScrollOffset(std::numeric_limits<float>::max(),
@@ -89,32 +62,26 @@ SnapContainerData::SnapContainerData(ScrollSnapType type)
proximity_range_(gfx::ScrollOffset(std::numeric_limits<float>::max(),
std::numeric_limits<float>::max())) {}
-SnapContainerData::SnapContainerData(ScrollSnapType type, gfx::ScrollOffset max)
+SnapContainerData::SnapContainerData(ScrollSnapType type,
+ const gfx::RectF& rect,
+ const gfx::ScrollOffset& max)
: scroll_snap_type_(type),
+ rect_(rect),
max_position_(max),
proximity_range_(gfx::ScrollOffset(std::numeric_limits<float>::max(),
std::numeric_limits<float>::max())) {}
SnapContainerData::SnapContainerData(const SnapContainerData& other) = default;
-SnapContainerData::SnapContainerData(SnapContainerData&& other)
- : scroll_snap_type_(other.scroll_snap_type_),
- max_position_(other.max_position_),
- proximity_range_(other.proximity_range_),
- snap_area_list_(std::move(other.snap_area_list_)) {}
+SnapContainerData::SnapContainerData(SnapContainerData&& other) = default;
SnapContainerData::~SnapContainerData() = default;
SnapContainerData& SnapContainerData::operator=(
const SnapContainerData& other) = default;
-SnapContainerData& SnapContainerData::operator=(SnapContainerData&& other) {
- scroll_snap_type_ = other.scroll_snap_type_;
- max_position_ = other.max_position_;
- proximity_range_ = other.proximity_range_;
- snap_area_list_ = std::move(other.snap_area_list_);
- return *this;
-}
+SnapContainerData& SnapContainerData::operator=(SnapContainerData&& other) =
+ default;
void SnapContainerData::AddSnapAreaData(SnapAreaData snap_area_data) {
snap_area_list_.push_back(snap_area_data);
@@ -131,18 +98,22 @@ bool SnapContainerData::FindSnapPosition(
if (!should_snap_on_x && !should_snap_on_y)
return false;
- base::Optional<SnapAreaData> closest_x, closest_y;
+ base::Optional<SnapSearchResult> closest_x, closest_y;
// A region that includes every reachable scroll position.
gfx::RectF scrollable_region(0, 0, max_position_.x(), max_position_.y());
if (should_snap_on_x) {
- closest_x = FindClosestValidArea(SearchAxis::kX, current_position,
- current_position, scrollable_region,
- proximity_range_, snap_area_list_);
+ // Start from current offset in the cross axis and assume it's always
+ // visible.
+ SnapSearchResult initial_snap_position_y = {
+ current_position.y(), SnapVisibleRange(0, max_position_.x())};
+ closest_x = FindClosestValidArea(SearchAxis::kX, current_position.x(),
+ initial_snap_position_y);
}
if (should_snap_on_y) {
- closest_y = FindClosestValidArea(SearchAxis::kY, current_position,
- current_position, scrollable_region,
- proximity_range_, snap_area_list_);
+ SnapSearchResult initial_snap_position_x = {
+ current_position.x(), SnapVisibleRange(0, max_position_.y())};
+ closest_y = FindClosestValidArea(SearchAxis::kY, current_position.y(),
+ initial_snap_position_x);
}
if (!closest_x.has_value() && !closest_y.has_value())
@@ -155,39 +126,160 @@ bool SnapContainerData::FindSnapPosition(
if (closest_x.has_value() && closest_y.has_value() &&
!IsMutualVisible(closest_x.value(), closest_y.value())) {
bool candidate_on_x_axis_is_closer =
- std::abs(closest_x.value().snap_position.x() - current_position.x()) <=
- std::abs(closest_y.value().snap_position.y() - current_position.y());
- if (candidate_on_x_axis_is_closer) {
- gfx::ScrollOffset snapped(closest_x.value().snap_position.x(),
- current_position.y());
- closest_y = FindClosestValidArea(
- SearchAxis::kY, current_position, snapped,
- closest_x.value().visible_region, proximity_range_, snap_area_list_);
- } else {
- gfx::ScrollOffset snapped(current_position.x(),
- closest_y.value().snap_position.y());
- closest_x = FindClosestValidArea(
- SearchAxis::kX, current_position, snapped,
- closest_y.value().visible_region, proximity_range_, snap_area_list_);
- }
+ std::abs(closest_x.value().snap_offset() - current_position.x()) <=
+ std::abs(closest_y.value().snap_offset() - current_position.y());
+ if (candidate_on_x_axis_is_closer)
+ closest_y = FindClosestValidArea(SearchAxis::kY, current_position.y(),
+ closest_x.value());
+ else
+ closest_x = FindClosestValidArea(SearchAxis::kX, current_position.x(),
+ closest_y.value());
}
*snap_position = current_position;
if (closest_x.has_value())
- snap_position->set_x(closest_x.value().snap_position.x());
+ snap_position->set_x(closest_x.value().snap_offset());
if (closest_y.has_value())
- snap_position->set_y(closest_y.value().snap_position.y());
-
+ snap_position->set_y(closest_y.value().snap_offset());
return true;
}
+base::Optional<SnapSearchResult> SnapContainerData::FindClosestValidArea(
+ SearchAxis axis,
+ float current_offset,
+ const SnapSearchResult& cros_axis_snap_result) const {
+ base::Optional<SnapSearchResult> result;
+ base::Optional<SnapSearchResult> inplace;
+ // The valid snap offsets immediately before and after the current offset.
+ float prev = std::numeric_limits<float>::lowest();
+ float next = std::numeric_limits<float>::max();
+ float smallest_distance =
+ axis == SearchAxis::kX ? proximity_range_.x() : proximity_range_.y();
+ for (const SnapAreaData& area : snap_area_list_) {
+ if (!SnappableOnAxis(area, axis))
+ continue;
+
+ SnapSearchResult candidate = GetSnapSearchResult(axis, area);
+ if (IsSnapportCoveredOnAxis(axis, current_offset, area.rect)) {
+ // Since snap area is currently covering the snapport, we consider the
+ // current offset as a valid snap position.
+ SnapSearchResult inplace_candidate = candidate;
+ inplace_candidate.set_snap_offset(current_offset);
+ if (IsMutualVisible(inplace_candidate, cros_axis_snap_result)) {
+ // If we've already found a valid overflowing area before, we enlarge
+ // the area's visible region.
+ if (inplace.has_value())
+ inplace.value().Union(inplace_candidate);
+ else
+ inplace = inplace_candidate;
+ // Even if a snap area covers the snapport, we need to continue this
+ // search to find previous and next snap positions and also to have
+ // alternative snap candidates if this inplace candidate is ultimately
+ // rejected. And this covering snap area has its own alignment that may
+ // generates a snap position rejecting the current inplace candidate.
+ }
+ }
+ if (!IsMutualVisible(candidate, cros_axis_snap_result))
+ continue;
+ float distance = std::abs(candidate.snap_offset() - current_offset);
+ if (distance < smallest_distance) {
+ smallest_distance = distance;
+ result = candidate;
+ }
+ if (candidate.snap_offset() < current_offset &&
+ candidate.snap_offset() > prev)
+ prev = candidate.snap_offset();
+ if (candidate.snap_offset() > current_offset &&
+ candidate.snap_offset() < next)
+ next = candidate.snap_offset();
+ }
+ // According to the spec [1], if the snap area is covering the snapport, the
+ // scroll offset is a valid snap position only if the distance between the
+ // geometrically previous and subsequent snap positions in that axis is larger
+ // than size of the snapport in that axis.
+ // [1] https://drafts.csswg.org/css-scroll-snap-1/#snap-overflow
+ float size = axis == SearchAxis::kX ? rect_.width() : rect_.height();
+ if (inplace.has_value() &&
+ (prev == std::numeric_limits<float>::lowest() ||
+ next == std::numeric_limits<float>::max() || next - prev > size)) {
+ return inplace;
+ }
+
+ return result;
+}
+
+SnapSearchResult SnapContainerData::GetSnapSearchResult(
+ SearchAxis axis,
+ const SnapAreaData& area) const {
+ SnapSearchResult result;
+ if (axis == SearchAxis::kX) {
+ result.set_visible_range(SnapVisibleRange(area.rect.y() - rect_.bottom(),
+ area.rect.bottom() - rect_.y()));
+ // https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-align
+ switch (area.scroll_snap_align.alignment_inline) {
+ case SnapAlignment::kStart:
+ result.set_snap_offset(area.rect.x() - rect_.x());
+ break;
+ case SnapAlignment::kCenter:
+ result.set_snap_offset(area.rect.CenterPoint().x() -
+ rect_.CenterPoint().x());
+ break;
+ case SnapAlignment::kEnd:
+ result.set_snap_offset(area.rect.right() - rect_.right());
+ break;
+ default:
+ NOTREACHED();
+ }
+ result.Clip(max_position_.x(), max_position_.y());
+ } else {
+ result.set_visible_range(SnapVisibleRange(area.rect.x() - rect_.right(),
+ area.rect.right() - rect_.x()));
+ switch (area.scroll_snap_align.alignment_block) {
+ case SnapAlignment::kStart:
+ result.set_snap_offset(area.rect.y() - rect_.y());
+ break;
+ case SnapAlignment::kCenter:
+ result.set_snap_offset(area.rect.CenterPoint().y() -
+ rect_.CenterPoint().y());
+ break;
+ case SnapAlignment::kEnd:
+ result.set_snap_offset(area.rect.bottom() - rect_.bottom());
+ break;
+ default:
+ NOTREACHED();
+ }
+ result.Clip(max_position_.y(), max_position_.x());
+ }
+ return result;
+}
+
+bool SnapContainerData::IsSnapportCoveredOnAxis(
+ SearchAxis axis,
+ float current_offset,
+ const gfx::RectF& area_rect) const {
+ if (axis == SearchAxis::kX) {
+ if (area_rect.width() < rect_.width())
+ return false;
+ float left = area_rect.x() - rect_.x();
+ float right = area_rect.right() - rect_.right();
+ return current_offset >= left && current_offset <= right;
+ } else {
+ if (area_rect.height() < rect_.height())
+ return false;
+ float top = area_rect.y() - rect_.y();
+ float bottom = area_rect.bottom() - rect_.bottom();
+ return current_offset >= top && current_offset <= bottom;
+ }
+}
+
std::ostream& operator<<(std::ostream& ostream, const SnapAreaData& area_data) {
- return ostream << area_data.snap_position.ToString() << "\t"
- << "visible in: " << area_data.visible_region.ToString();
+ return ostream << area_data.rect.ToString();
}
std::ostream& operator<<(std::ostream& ostream,
const SnapContainerData& container_data) {
+ ostream << "container_rect: " << container_data.rect().ToString();
+ ostream << "area_rects: ";
for (size_t i = 0; i < container_data.size(); ++i) {
ostream << container_data.at(i) << "\n";
}
diff --git a/chromium/cc/input/scroll_snap_data.h b/chromium/cc/input/scroll_snap_data.h
index dbc0b9128f5..e44b9d882e2 100644
--- a/chromium/cc/input/scroll_snap_data.h
+++ b/chromium/cc/input/scroll_snap_data.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "base/optional.h"
#include "cc/cc_export.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
@@ -84,6 +85,50 @@ struct ScrollSnapAlign {
SnapAlignment alignment_block;
};
+// We should really use gfx::RangeF. However, it includes windows.h which would
+// bring in complexity to the compilation. https://crbug.com/855717
+class SnapVisibleRange {
+ public:
+ SnapVisibleRange() {}
+ SnapVisibleRange(float start, float end) : start_(start), end_(end) {}
+ bool Contains(float value) const;
+ float start() const { return start_; }
+ float end() const { return end_; }
+
+ private:
+ float start_;
+ float end_;
+};
+
+// This class includes snap offset and visible range needed to perform a snap
+// operation on one axis for a specific area. The data can be used to determine
+// whether this snap area provides a valid snap position for the current scroll.
+class SnapSearchResult {
+ public:
+ SnapSearchResult() {}
+ SnapSearchResult(float offset, const SnapVisibleRange& range);
+ // Clips the |snap_offset| between 0 and |max_snap|. And clips the
+ // |visible_range| between 0 and |max_visible|.
+ void Clip(float max_snap, float max_visible);
+
+ // Union the visible_range of the two SnapSearchResult if they represent two
+ // snap areas that are both covering the snapport at the current offset.
+ void Union(const SnapSearchResult& other);
+
+ float snap_offset() const { return snap_offset_; }
+ void set_snap_offset(float offset) { snap_offset_ = offset; }
+
+ SnapVisibleRange visible_range() const { return visible_range_; }
+ void set_visible_range(const SnapVisibleRange& range);
+
+ private:
+ float snap_offset_;
+ // This is the range on the cross axis, within which the SnapArea generating
+ // this |snap_offset| is visible. We expect the range to be in order (as
+ // opposed to reversed), i.e., start < end.
+ SnapVisibleRange visible_range_;
+};
+
// Snap area is a bounding box that could be snapped to when a scroll happens in
// its scroll container.
// This data structure describes the data needed for SnapCoordinator if we want
@@ -96,45 +141,27 @@ struct SnapAreaData {
SnapAreaData() {}
- SnapAreaData(SnapAxis axis,
- gfx::ScrollOffset position,
- gfx::RectF visible,
- bool msnap)
- : snap_axis(axis),
- snap_position(position),
- visible_region(visible),
- must_snap(msnap) {}
+ SnapAreaData(const ScrollSnapAlign& align, const gfx::RectF& rec, bool msnap)
+ : scroll_snap_align(align), rect(rec), must_snap(msnap) {}
bool operator==(const SnapAreaData& other) const {
- return (other.snap_axis == snap_axis) &&
- (other.snap_position == snap_position) &&
- (other.visible_region == visible_region) &&
- (other.must_snap == must_snap);
+ return (other.scroll_snap_align == scroll_snap_align) &&
+ (other.rect == rect) && (other.must_snap == must_snap);
}
bool operator!=(const SnapAreaData& other) const { return !(*this == other); }
- // The axes along which the area has specified snap positions.
- SnapAxis snap_axis;
-
- // The scroll_position to snap the area at the specified alignment in that
- // axis.
- // This is in the same coordinate with blink's scroll position, which is the
- // location of the top/left of the scroll viewport in the top/left of the
- // overflow rect.
- gfx::ScrollOffset snap_position;
+ // Specifies how the snap area should be aligned with its snap container when
+ // snapped. The alignment_inline and alignment_block represent the alignments
+ // on x axis and y axis repectively.
+ ScrollSnapAlign scroll_snap_align;
- // The area is only visible when the current scroll offset is within
- // |visible_region|.
- // See https://drafts.csswg.org/css-scroll-snap-1/#snap-scope
- gfx::RectF visible_region;
+ // The snap area rect relative to its snap container's boundary
+ gfx::RectF rect;
// Whether this area has scroll-snap-stop: always.
// See https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-stop
bool must_snap;
-
- // TODO(sunyunjia): Add fields for visibility requirement and large area
- // snapping.
};
typedef std::vector<SnapAreaData> SnapAreaList;
@@ -148,7 +175,9 @@ class CC_EXPORT SnapContainerData {
public:
SnapContainerData();
explicit SnapContainerData(ScrollSnapType type);
- SnapContainerData(ScrollSnapType type, gfx::ScrollOffset max);
+ SnapContainerData(ScrollSnapType type,
+ const gfx::RectF& rect,
+ const gfx::ScrollOffset& max);
SnapContainerData(const SnapContainerData& other);
SnapContainerData(SnapContainerData&& other);
~SnapContainerData();
@@ -158,7 +187,7 @@ class CC_EXPORT SnapContainerData {
bool operator==(const SnapContainerData& other) const {
return (other.scroll_snap_type_ == scroll_snap_type_) &&
- (other.max_position_ == max_position_) &&
+ (other.rect_ == rect_) && (other.max_position_ == max_position_) &&
(other.proximity_range_ == proximity_range_) &&
(other.snap_area_list_ == snap_area_list_);
}
@@ -179,6 +208,9 @@ class CC_EXPORT SnapContainerData {
void set_scroll_snap_type(ScrollSnapType type) { scroll_snap_type_ = type; }
ScrollSnapType scroll_snap_type() const { return scroll_snap_type_; }
+ void set_rect(const gfx::RectF& rect) { rect_ = rect; }
+ gfx::RectF rect() const { return rect_; }
+
void set_max_position(gfx::ScrollOffset position) {
max_position_ = position;
}
@@ -190,11 +222,42 @@ class CC_EXPORT SnapContainerData {
gfx::ScrollOffset proximity_range() const { return proximity_range_; }
private:
+ // Finds the best SnapArea candidate that minimizes the distance between
+ // current and candidate positions, while satisfying two invariants:
+ // - |candidate.snap_offset| is within |cross_axis_snap_result|'s visible
+ // range on |axis|.
+ // - |cross_axis_snap_result.snap_offset| is within |candidate|'s visible
+ // range on the cross axis.
+ // |cross_axis_snap_result| is what we've found to snap on the cross axis,
+ // or the original scroll offset if this is the first iteration of search.
+ // Returns the candidate as SnapSearchResult that includes the area's
+ // |snap_offset| and its visible range on the cross axis.
+ base::Optional<SnapSearchResult> FindClosestValidArea(
+ SearchAxis axis,
+ float current_offset,
+ const SnapSearchResult& cross_axis_snap_result) const;
+
+ // Returns all the info needed to snap at this area on the given axis,
+ // including:
+ // - The offset at which the snap area and the snap container meet the
+ // requested alignment.
+ // - The visible range within which the snap area is visible on the cross
+ // axis.
+ SnapSearchResult GetSnapSearchResult(SearchAxis axis,
+ const SnapAreaData& data) const;
+
+ bool IsSnapportCoveredOnAxis(SearchAxis axis,
+ float current_offset,
+ const gfx::RectF& area_rect) const;
+
// Specifies whether a scroll container is a scroll snap container, how
// strictly it snaps, and which axes are considered.
// See https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-type for details.
ScrollSnapType scroll_snap_type_;
+ // The rect of the snap_container relative to its boundary.
+ gfx::RectF rect_;
+
// The maximal scroll position of the SnapContainer, in the same coordinate
// with blink's scroll position.
gfx::ScrollOffset max_position_;
diff --git a/chromium/cc/input/scroll_snap_data_unittest.cc b/chromium/cc/input/scroll_snap_data_unittest.cc
index 794f83faeaf..a688448ab2d 100644
--- a/chromium/cc/input/scroll_snap_data_unittest.cc
+++ b/chromium/cc/input/scroll_snap_data_unittest.cc
@@ -10,93 +10,158 @@ namespace cc {
class ScrollSnapDataTest : public testing::Test {};
+TEST_F(ScrollSnapDataTest, StartAlignmentCalculation) {
+ SnapContainerData container(
+ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
+ gfx::RectF(10, 10, 200, 300), gfx::ScrollOffset(600, 800));
+ SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart),
+ gfx::RectF(100, 150, 100, 100), false);
+ container.AddSnapAreaData(area);
+ gfx::ScrollOffset current_position(0, 0);
+ gfx::ScrollOffset snap_position;
+ EXPECT_TRUE(
+ container.FindSnapPosition(current_position, true, true, &snap_position));
+ EXPECT_EQ(90, snap_position.x());
+ EXPECT_EQ(140, snap_position.y());
+}
+
+TEST_F(ScrollSnapDataTest, CenterAlignmentCalculation) {
+ SnapContainerData container(
+ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
+ gfx::RectF(10, 10, 200, 300), gfx::ScrollOffset(600, 800));
+ SnapAreaData area(ScrollSnapAlign(SnapAlignment::kCenter),
+ gfx::RectF(100, 150, 100, 100), false);
+ container.AddSnapAreaData(area);
+ gfx::ScrollOffset current_position(0, 0);
+ gfx::ScrollOffset snap_position;
+ EXPECT_TRUE(
+ container.FindSnapPosition(current_position, true, true, &snap_position));
+ EXPECT_EQ(40, snap_position.x());
+ EXPECT_EQ(40, snap_position.y());
+}
+
+TEST_F(ScrollSnapDataTest, EndAlignmentCalculation) {
+ SnapContainerData container(
+ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
+ gfx::RectF(10, 10, 200, 200), gfx::ScrollOffset(600, 800));
+ SnapAreaData area(ScrollSnapAlign(SnapAlignment::kEnd),
+ gfx::RectF(150, 200, 100, 100), false);
+ container.AddSnapAreaData(area);
+ gfx::ScrollOffset current_position(0, 0);
+ gfx::ScrollOffset snap_position;
+ EXPECT_TRUE(
+ container.FindSnapPosition(current_position, true, true, &snap_position));
+ EXPECT_EQ(40, snap_position.x());
+ EXPECT_EQ(90, snap_position.y());
+}
+
+TEST_F(ScrollSnapDataTest, UnreachableSnapPositionCalculation) {
+ SnapContainerData container(
+ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
+ gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(100, 100));
+ SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kEnd),
+ gfx::RectF(200, 0, 100, 100), false);
+ container.AddSnapAreaData(area);
+ gfx::ScrollOffset current_position(50, 50);
+ gfx::ScrollOffset snap_position;
+ EXPECT_TRUE(
+ container.FindSnapPosition(current_position, true, true, &snap_position));
+ // Aligning to start on x would lead the scroll offset larger than max, and
+ // aligning to end on y would lead the scroll offset smaller than zero. So
+ // we expect these are clamped.
+ EXPECT_EQ(100, snap_position.x());
+ EXPECT_EQ(0, snap_position.y());
+}
+
TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionIndependently) {
- SnapContainerData data(
+ SnapContainerData container(
ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
- gfx::ScrollOffset(360, 380));
- gfx::ScrollOffset current_position(100, 100);
+ gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800));
SnapAreaData snap_x_only(
- SnapAxis::kX, gfx::ScrollOffset(80, SnapAreaData::kInvalidScrollPosition),
- gfx::RectF(0, 0, 360, 380), false);
+ ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone),
+ gfx::RectF(80, 0, 150, 150), false);
SnapAreaData snap_y_only(
- SnapAxis::kY, gfx::ScrollOffset(SnapAreaData::kInvalidScrollPosition, 70),
- gfx::RectF(0, 0, 360, 380), false);
- SnapAreaData snap_on_both(SnapAxis::kBoth, gfx::ScrollOffset(50, 150),
- gfx::RectF(0, 0, 360, 380), false);
- data.AddSnapAreaData(snap_x_only);
- data.AddSnapAreaData(snap_y_only);
- data.AddSnapAreaData(snap_on_both);
+ ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart),
+ gfx::RectF(0, 70, 150, 150), false);
+ SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart),
+ gfx::RectF(50, 150, 150, 150), false);
+ gfx::ScrollOffset current_position(100, 100);
+ container.AddSnapAreaData(snap_x_only);
+ container.AddSnapAreaData(snap_y_only);
+ container.AddSnapAreaData(snap_on_both);
gfx::ScrollOffset snap_position;
EXPECT_TRUE(
- data.FindSnapPosition(current_position, true, true, &snap_position));
+ container.FindSnapPosition(current_position, true, true, &snap_position));
EXPECT_EQ(80, snap_position.x());
EXPECT_EQ(70, snap_position.y());
}
TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionOnAxisValueBoth) {
- SnapContainerData data(
+ SnapContainerData container(
ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
- gfx::ScrollOffset(360, 380));
- gfx::ScrollOffset current_position(40, 150);
+ gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800));
SnapAreaData snap_x_only(
- SnapAxis::kX, gfx::ScrollOffset(80, SnapAreaData::kInvalidScrollPosition),
- gfx::RectF(0, 0, 360, 380), false);
+ ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone),
+ gfx::RectF(80, 0, 150, 150), false);
SnapAreaData snap_y_only(
- SnapAxis::kY, gfx::ScrollOffset(SnapAreaData::kInvalidScrollPosition, 70),
- gfx::RectF(0, 0, 360, 380), false);
- SnapAreaData snap_on_both(SnapAxis::kBoth, gfx::ScrollOffset(50, 150),
- gfx::RectF(0, 0, 360, 380), false);
- data.AddSnapAreaData(snap_x_only);
- data.AddSnapAreaData(snap_y_only);
- data.AddSnapAreaData(snap_on_both);
+ ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart),
+ gfx::RectF(0, 70, 150, 150), false);
+ SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart),
+ gfx::RectF(50, 150, 150, 150), false);
+ gfx::ScrollOffset current_position(40, 120);
+ container.AddSnapAreaData(snap_x_only);
+ container.AddSnapAreaData(snap_y_only);
+ container.AddSnapAreaData(snap_on_both);
gfx::ScrollOffset snap_position;
EXPECT_TRUE(
- data.FindSnapPosition(current_position, true, true, &snap_position));
+ container.FindSnapPosition(current_position, true, true, &snap_position));
EXPECT_EQ(50, snap_position.x());
EXPECT_EQ(150, snap_position.y());
}
TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonScrolledAxis) {
- SnapContainerData data(
+ SnapContainerData container(
ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
- gfx::ScrollOffset(360, 380));
- gfx::ScrollOffset current_position(100, 100);
+ gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800));
SnapAreaData snap_x_only(
- SnapAxis::kX, gfx::ScrollOffset(80, SnapAreaData::kInvalidScrollPosition),
- gfx::RectF(0, 0, 360, 380), false);
+ ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone),
+ gfx::RectF(80, 0, 150, 150), false);
SnapAreaData snap_y_only(
- SnapAxis::kY, gfx::ScrollOffset(SnapAreaData::kInvalidScrollPosition, 70),
- gfx::RectF(0, 0, 360, 380), false);
- data.AddSnapAreaData(snap_x_only);
- data.AddSnapAreaData(snap_y_only);
+ ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart),
+ gfx::RectF(0, 70, 150, 150), false);
+ gfx::ScrollOffset current_position(100, 100);
+ container.AddSnapAreaData(snap_x_only);
+ container.AddSnapAreaData(snap_y_only);
gfx::ScrollOffset snap_position;
- EXPECT_TRUE(
- data.FindSnapPosition(current_position, true, false, &snap_position));
+ EXPECT_TRUE(container.FindSnapPosition(current_position, true, false,
+ &snap_position));
EXPECT_EQ(80, snap_position.x());
EXPECT_EQ(100, snap_position.y());
}
TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonVisibleAreas) {
- SnapContainerData data(
+ SnapContainerData container(
ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
- gfx::ScrollOffset(360, 380));
- gfx::ScrollOffset current_position(100, 100);
- SnapAreaData non_visible_x(SnapAxis::kBoth, gfx::ScrollOffset(70, 70),
- gfx::RectF(0, 0, 90, 200), false);
- SnapAreaData non_visible_y(SnapAxis::kBoth, gfx::ScrollOffset(70, 70),
- gfx::RectF(0, 0, 200, 90), false);
- data.AddSnapAreaData(non_visible_x);
- data.AddSnapAreaData(non_visible_y);
+ gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800));
+ SnapAreaData snap_x_only(
+ ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone),
+ gfx::RectF(300, 400, 100, 100), false);
+ SnapAreaData snap_y_only(
+ ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart),
+ gfx::RectF(400, 300, 100, 100), false);
+ gfx::ScrollOffset current_position(0, 0);
+ container.AddSnapAreaData(snap_x_only);
+ container.AddSnapAreaData(snap_y_only);
gfx::ScrollOffset snap_position;
EXPECT_FALSE(
- data.FindSnapPosition(current_position, true, true, &snap_position));
+ container.FindSnapPosition(current_position, true, true, &snap_position));
}
TEST_F(ScrollSnapDataTest, SnapOnClosestAxisFirstIfVisibilityConflicts) {
- SnapContainerData data(
+ SnapContainerData container(
ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
- gfx::ScrollOffset(360, 380));
- gfx::ScrollOffset current_position(100, 100);
+ gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800));
+ gfx::ScrollOffset current_position(0, 0);
// Both the areas are currently visible.
// However, if we snap to them on x and y independently, none is visible after
@@ -104,38 +169,37 @@ TEST_F(ScrollSnapDataTest, SnapOnClosestAxisFirstIfVisibilityConflicts) {
// After that, we look for another snap point on y axis which does not
// conflict with the snap point on x.
SnapAreaData snap_x(
- SnapAxis::kX, gfx::ScrollOffset(80, SnapAreaData::kInvalidScrollPosition),
- gfx::RectF(60, 60, 60, 60), false);
+ ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone),
+ gfx::RectF(150, 0, 100, 100), false);
SnapAreaData snap_y1(
- SnapAxis::kY,
- gfx::ScrollOffset(SnapAreaData::kInvalidScrollPosition, 130),
- gfx::RectF(90, 90, 60, 60), false);
+ ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart),
+ gfx::RectF(0, 180, 100, 100), false);
SnapAreaData snap_y2(
- SnapAxis::kY, gfx::ScrollOffset(SnapAreaData::kInvalidScrollPosition, 60),
- gfx::RectF(50, 50, 60, 60), false);
- data.AddSnapAreaData(snap_x);
- data.AddSnapAreaData(snap_y1);
- data.AddSnapAreaData(snap_y2);
+ ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart),
+ gfx::RectF(250, 80, 100, 100), false);
+ container.AddSnapAreaData(snap_x);
+ container.AddSnapAreaData(snap_y1);
+ container.AddSnapAreaData(snap_y2);
gfx::ScrollOffset snap_position;
EXPECT_TRUE(
- data.FindSnapPosition(current_position, true, true, &snap_position));
- EXPECT_EQ(80, snap_position.x());
- EXPECT_EQ(60, snap_position.y());
+ container.FindSnapPosition(current_position, true, true, &snap_position));
+ EXPECT_EQ(150, snap_position.x());
+ EXPECT_EQ(80, snap_position.y());
}
TEST_F(ScrollSnapDataTest, DoesNotSnapToPositionsOutsideProximityRange) {
- SnapContainerData data(
+ SnapContainerData container(
ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
- gfx::ScrollOffset(360, 380));
- data.set_proximity_range(gfx::ScrollOffset(50, 50));
+ gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800));
+ container.set_proximity_range(gfx::ScrollOffset(50, 50));
gfx::ScrollOffset current_position(100, 100);
- SnapAreaData area(SnapAxis::kBoth, gfx::ScrollOffset(80, 160),
- gfx::RectF(50, 50, 200, 200), false);
- data.AddSnapAreaData(area);
+ SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart),
+ gfx::RectF(80, 160, 100, 100), false);
+ container.AddSnapAreaData(area);
gfx::ScrollOffset snap_position;
EXPECT_TRUE(
- data.FindSnapPosition(current_position, true, true, &snap_position));
+ container.FindSnapPosition(current_position, true, true, &snap_position));
// The snap position on x, 80, is within the proximity range of [50, 150].
// However, the snap position on y, 160, is outside the proximity range of
diff --git a/chromium/cc/input/snap_fling_controller.h b/chromium/cc/input/snap_fling_controller.h
index 5199b23faa6..20f305651c2 100644
--- a/chromium/cc/input/snap_fling_controller.h
+++ b/chromium/cc/input/snap_fling_controller.h
@@ -24,8 +24,8 @@ class SnapFlingCurve;
class SnapFlingClient {
public:
virtual bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement,
- gfx::Vector2dF* initial_offset,
- gfx::Vector2dF* target_offset) const = 0;
+ gfx::Vector2dF* out_initial_offset,
+ gfx::Vector2dF* out_target_offset) const = 0;
virtual gfx::Vector2dF ScrollByForSnapFling(const gfx::Vector2dF& delta) = 0;
virtual void ScrollEndForSnapFling() = 0;
virtual void RequestAnimationForSnapFling() = 0;
diff --git a/chromium/cc/input/snap_fling_curve.cc b/chromium/cc/input/snap_fling_curve.cc
index 645c9c5440a..b61be7b9925 100644
--- a/chromium/cc/input/snap_fling_curve.cc
+++ b/chromium/cc/input/snap_fling_curve.cc
@@ -4,6 +4,7 @@
#include "cc/input/snap_fling_curve.h"
+#include <algorithm>
#include <cmath>
#include "build/build_config.h"
@@ -43,6 +44,11 @@ double CalculateFirstDelta(double distance, double frames) {
return distance * (1 - kRatio) / (1 - std::pow(kRatio, frames));
}
+bool IsWithinOnePixel(gfx::Vector2dF actual, gfx::Vector2dF target) {
+ return std::abs(actual.x() - target.x()) < 1 &&
+ std::abs(actual.y() - target.y()) < 1;
+}
+
} // namespace
gfx::Vector2dF SnapFlingCurve::EstimateDisplacement(
@@ -71,16 +77,7 @@ SnapFlingCurve::SnapFlingCurve(const gfx::Vector2dF& start_offset,
SnapFlingCurve::~SnapFlingCurve() = default;
-double SnapFlingCurve::GetCurrentCurveDistance(base::TimeTicks time_stamp) {
- double current_distance = GetDistanceFromDisplacement(current_displacement_);
- base::TimeDelta current_time = time_stamp - start_time_;
-
- // Finishes the curve if the time elapsed is longer than |duration_|, or the
- // remaining distance is less than 1.
- if (current_time >= duration_ || current_distance >= total_distance_ - 1) {
- return total_distance_;
- }
-
+double SnapFlingCurve::GetCurrentCurveDistance(base::TimeDelta current_time) {
double current_frame = current_time.InMillisecondsF() / kMsPerFrame + 1;
double sum =
first_delta_ * (1 - std::pow(kRatio, current_frame)) / (1 - kRatio);
@@ -93,13 +90,15 @@ gfx::Vector2dF SnapFlingCurve::GetScrollDelta(base::TimeTicks time_stamp) {
// The the snap offset may never be reached due to clamping or other factors.
// To avoid a never ending snap curve, we force the curve to end if the time
- // has passed a maximum Duration.
- if (time_stamp - start_time_ > kMaximumSnapDuration) {
+ // has passed |duration_| or the remaining displacement is less than 1.
+ base::TimeDelta current_time = time_stamp - start_time_;
+ if (current_time >= std::min(duration_, kMaximumSnapDuration) ||
+ IsWithinOnePixel(current_displacement_, total_displacement_)) {
is_finished_ = true;
return total_displacement_ - current_displacement_;
}
- double new_distance = GetCurrentCurveDistance(time_stamp);
+ double new_distance = GetCurrentCurveDistance(current_time);
gfx::Vector2dF new_displacement(new_distance * ratio_x_,
new_distance * ratio_y_);
@@ -108,8 +107,6 @@ gfx::Vector2dF SnapFlingCurve::GetScrollDelta(base::TimeTicks time_stamp) {
void SnapFlingCurve::UpdateCurrentOffset(const gfx::Vector2dF& current_offset) {
current_displacement_ = current_offset - start_offset_;
- if (current_displacement_ == total_displacement_)
- is_finished_ = true;
}
bool SnapFlingCurve::IsFinished() const {
diff --git a/chromium/cc/input/snap_fling_curve.h b/chromium/cc/input/snap_fling_curve.h
index b5eaf62fa3d..4aad8d1ef70 100644
--- a/chromium/cc/input/snap_fling_curve.h
+++ b/chromium/cc/input/snap_fling_curve.h
@@ -41,8 +41,8 @@ class CC_EXPORT SnapFlingCurve {
base::TimeDelta duration() const { return duration_; }
private:
- // Returns the curve's current distance at |time_stamp|.
- double GetCurrentCurveDistance(base::TimeTicks time_stamp);
+ // Returns the curve's current distance at |current_time|.
+ double GetCurrentCurveDistance(base::TimeDelta current_time);
// The initial scroll offset of the scroller.
const gfx::Vector2dF start_offset_;
diff --git a/chromium/cc/input/snap_fling_curve_unittest.cc b/chromium/cc/input/snap_fling_curve_unittest.cc
index 028006f7670..3682ded6657 100644
--- a/chromium/cc/input/snap_fling_curve_unittest.cc
+++ b/chromium/cc/input/snap_fling_curve_unittest.cc
@@ -40,15 +40,12 @@ TEST(SnapFlingCurveTest, AdvanceHalfwayThrough) {
EXPECT_FALSE(curve.IsFinished());
}
-TEST(SnapFlingCurveTest, AdvanceFullyThroughOnlyFinishesAfterUpdate) {
+TEST(SnapFlingCurveTest, AdvanceFullyThrough) {
SnapFlingCurve curve(gfx::Vector2dF(100, 100), gfx::Vector2dF(500, 500),
base::TimeTicks());
gfx::Vector2dF delta =
curve.GetScrollDelta(base::TimeTicks() + curve.duration());
EXPECT_EQ(gfx::Vector2dF(400, 400), delta);
- EXPECT_FALSE(curve.IsFinished());
-
- curve.UpdateCurrentOffset(gfx::Vector2dF(500, 500));
EXPECT_TRUE(curve.IsFinished());
}
@@ -56,8 +53,6 @@ TEST(SnapFlingCurveTest, ReturnsZeroAfterFinished) {
SnapFlingCurve curve(gfx::Vector2dF(100, 100), gfx::Vector2dF(500, 500),
base::TimeTicks());
curve.UpdateCurrentOffset(gfx::Vector2dF(500, 500));
- EXPECT_TRUE(curve.IsFinished());
-
gfx::Vector2dF delta = curve.GetScrollDelta(base::TimeTicks());
EXPECT_EQ(gfx::Vector2dF(), delta);
EXPECT_TRUE(curve.IsFinished());
@@ -67,5 +62,20 @@ TEST(SnapFlingCurveTest, ReturnsZeroAfterFinished) {
EXPECT_TRUE(curve.IsFinished());
}
+TEST(SnapFlingCurveTest, FlingFinishesWithinOnePixel) {
+ SnapFlingCurve curve(gfx::Vector2dF(0, 0), gfx::Vector2dF(100.5, 99.5),
+ base::TimeTicks());
+ EXPECT_FALSE(curve.IsFinished());
+
+ curve.UpdateCurrentOffset(gfx::Vector2dF(99, 101));
+ // IsFinished() is updated in GetScrollDelta().
+ curve.GetScrollDelta(base::TimeTicks());
+ EXPECT_FALSE(curve.IsFinished());
+
+ curve.UpdateCurrentOffset(gfx::Vector2dF(100, 100));
+ curve.GetScrollDelta(base::TimeTicks());
+ EXPECT_TRUE(curve.IsFinished());
+}
+
} // namespace test
} // 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 890f7ec426c..c45a685da4f 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -136,9 +136,11 @@ class HudSoftwareBacking : public ResourcePool::SoftwareBacking {
bool HeadsUpDisplayLayerImpl::WillDraw(
DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) {
- if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
+ viz::ClientResourceProvider* resource_provider) {
+ if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE &&
+ !LayerImpl::WillDraw(draw_mode, resource_provider)) {
return false;
+ }
int max_texture_size = layer_tree_impl()->max_texture_size();
internal_contents_scale_ = GetIdealContentsScale();
@@ -147,7 +149,7 @@ bool HeadsUpDisplayLayerImpl::WillDraw(
internal_content_bounds_.SetToMin(
gfx::Size(max_texture_size, max_texture_size));
- return LayerImpl::WillDraw(draw_mode, resource_provider);
+ return true;
}
void HeadsUpDisplayLayerImpl::AppendQuads(viz::RenderPass* render_pass,
@@ -173,7 +175,7 @@ void HeadsUpDisplayLayerImpl::AppendQuads(viz::RenderPass* render_pass,
void HeadsUpDisplayLayerImpl::UpdateHudTexture(
DrawMode draw_mode,
LayerTreeFrameSink* layer_tree_frame_sink,
- LayerTreeResourceProvider* resource_provider,
+ viz::ClientResourceProvider* resource_provider,
bool gpu_raster,
const viz::RenderPassList& list) {
if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
@@ -231,7 +233,6 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
backing->texture_id = alloc.texture_id;
backing->texture_target = alloc.texture_target;
backing->overlay_candidate = alloc.overlay_candidate;
- backing->mailbox = gpu::Mailbox::Generate();
context_provider->ContextGL()->ProduceTextureDirectCHROMIUM(
backing->texture_id, backing->mailbox.name);
pool_resource.set_gpu_backing(std::move(backing));
@@ -276,7 +277,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
{
ScopedGpuRaster gpu_raster(context_provider);
- LayerTreeResourceProvider::ScopedSkSurface scoped_surface(
+ viz::ClientResourceProvider::ScopedSkSurface scoped_surface(
context_provider->GrContext(), backing->texture_id,
backing->texture_target, pool_resource.size(), pool_resource.format(),
false /* can_use_lcd_text */, 0 /* msaa_sample_count */);
@@ -289,7 +290,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
}
backing->mailbox_sync_token =
- LayerTreeResourceProvider::GenerateSyncTokenHelper(gl);
+ viz::ClientResourceProvider::GenerateSyncTokenHelper(gl);
} else if (draw_mode == DRAW_MODE_HARDWARE) {
// If not using |gpu_raster| but using gpu compositing, we DrawHudContents()
// into a software bitmap and upload it to a texture for compositing.
@@ -312,12 +313,13 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
SkPixmap pixmap;
staging_surface_->peekPixels(&pixmap);
gl->BindTexture(backing->texture_target, backing->texture_id);
+ DCHECK(GLSupportsFormat(pool_resource.format()));
gl->TexSubImage2D(
backing->texture_target, 0, 0, 0, pool_resource.size().width(),
pool_resource.size().height(), GLDataFormat(pool_resource.format()),
GLDataType(pool_resource.format()), pixmap.addr());
backing->mailbox_sync_token =
- LayerTreeResourceProvider::GenerateSyncTokenHelper(gl);
+ viz::ClientResourceProvider::GenerateSyncTokenHelper(gl);
} else {
// If not using gpu compositing, we DrawHudContents() directly into a shared
// memory bitmap, wrapped in an SkSurface, that can be shared to the display
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h
index b6f5070ddd3..6102b0da115 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.h
+++ b/chromium/cc/layers/heads_up_display_layer_impl.h
@@ -24,10 +24,13 @@ class SkPaint;
class SkTypeface;
struct SkRect;
+namespace viz {
+class ClientResourceProvider;
+}
+
namespace cc {
class FrameRateCounter;
class LayerTreeFrameSink;
-class LayerTreeResourceProvider;
class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
public:
@@ -41,12 +44,12 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
bool WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) override;
+ viz::ClientResourceProvider* resource_provider) override;
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
void UpdateHudTexture(DrawMode draw_mode,
LayerTreeFrameSink* frame_sink,
- LayerTreeResourceProvider* resource_provider,
+ viz::ClientResourceProvider* resource_provider,
bool gpu_raster,
const viz::RenderPassList& list);
diff --git a/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc b/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
index 6397ea81bb0..f5dc43ee1bb 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
@@ -18,7 +18,7 @@ namespace {
void CheckDrawLayer(HeadsUpDisplayLayerImpl* layer,
LayerTreeFrameSink* frame_sink,
- LayerTreeResourceProvider* resource_provider,
+ viz::ClientResourceProvider* resource_provider,
viz::ContextProvider* context_provider,
DrawMode draw_mode) {
std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create();
@@ -47,10 +47,11 @@ TEST(HeadsUpDisplayLayerImplTest, ResourcelessSoftwareDrawAfterResourceLoss) {
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.CreatePendingTree();
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
std::unique_ptr<HeadsUpDisplayLayerImpl> layer_ptr =
HeadsUpDisplayLayerImpl::Create(host_impl.pending_tree(), 1);
layer_ptr->SetBounds(gfx::Size(100, 100));
+ layer_ptr->set_visible_layer_rect(gfx::Rect(100, 100));
HeadsUpDisplayLayerImpl* layer = layer_ptr.get();
@@ -80,10 +81,11 @@ TEST(HeadsUpDisplayLayerImplTest, CPUAndGPURasterCanvas) {
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.CreatePendingTree();
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
std::unique_ptr<HeadsUpDisplayLayerImpl> layer_ptr =
HeadsUpDisplayLayerImpl::Create(host_impl.pending_tree(), 1);
layer_ptr->SetBounds(gfx::Size(100, 100));
+ layer_ptr->set_visible_layer_rect(gfx::Rect(100, 100));
HeadsUpDisplayLayerImpl* layer = layer_ptr.get();
@@ -97,7 +99,7 @@ TEST(HeadsUpDisplayLayerImplTest, CPUAndGPURasterCanvas) {
host_impl.ReleaseLayerTreeFrameSink();
layer_tree_frame_sink = FakeLayerTreeFrameSink::CreateSoftware();
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
// Check SW canvas drawing is ok.
CheckDrawLayer(layer, host_impl.layer_tree_frame_sink(),
diff --git a/chromium/cc/layers/heads_up_display_unittest.cc b/chromium/cc/layers/heads_up_display_unittest.cc
index b1e7368d8bd..840f82f8ef4 100644
--- a/chromium/cc/layers/heads_up_display_unittest.cc
+++ b/chromium/cc/layers/heads_up_display_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "cc/layers/heads_up_display_layer.h"
+
#include "cc/layers/layer.h"
#include "cc/test/layer_tree_test.h"
#include "cc/trees/layer_tree_host.h"
@@ -18,26 +19,11 @@ class HeadsUpDisplayTest : public LayerTreeTest {
}
};
-class DrawsContentLayer : public Layer {
- public:
- static scoped_refptr<DrawsContentLayer> Create() {
- return base::WrapRefCounted(new DrawsContentLayer());
- }
- bool DrawsContent() const override { return true; }
-
- private:
- DrawsContentLayer() = default;
- ~DrawsContentLayer() override = default;
-};
-
class HudWithRootLayerChange : public HeadsUpDisplayTest {
public:
- HudWithRootLayerChange()
- : root_layer1_(DrawsContentLayer::Create()),
- root_layer2_(DrawsContentLayer::Create()),
- num_commits_(0) {}
-
void BeginTest() override {
+ root_layer1_ = Layer::Create();
+ root_layer2_ = Layer::Create();
root_layer1_->SetBounds(gfx::Size(30, 30));
root_layer2_->SetBounds(gfx::Size(30, 30));
@@ -76,7 +62,7 @@ class HudWithRootLayerChange : public HeadsUpDisplayTest {
break;
case 6:
EXPECT_EQ(root_layer2_.get(), layer_tree_host()->hud_layer()->parent());
- // Change directly back to the last root layer/
+ // Change directly back to the last root layer.
layer_tree_host()->SetRootLayer(root_layer1_);
break;
case 7:
@@ -89,12 +75,12 @@ class HudWithRootLayerChange : public HeadsUpDisplayTest {
void AfterTest() override {}
private:
- scoped_refptr<DrawsContentLayer> root_layer1_;
- scoped_refptr<DrawsContentLayer> root_layer2_;
- int num_commits_;
+ scoped_refptr<Layer> root_layer1_;
+ scoped_refptr<Layer> root_layer2_;
+ int num_commits_ = 0;
};
-MULTI_THREAD_TEST_F(HudWithRootLayerChange);
+SINGLE_AND_MULTI_THREAD_TEST_F(HudWithRootLayerChange);
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index c5fb253d85e..823a5df49c7 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -19,7 +19,7 @@
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/layers/layer_client.h"
#include "cc/layers/layer_impl.h"
-#include "cc/layers/scrollbar_layer_interface.h"
+#include "cc/layers/picture_layer.h"
#include "cc/tiles/frame_viewer_instrumentation.h"
#include "cc/trees/draw_property_utils.h"
#include "cc/trees/effect_node.h"
@@ -85,7 +85,7 @@ Layer::Layer()
clip_tree_index_(ClipTree::kInvalidNodeId),
scroll_tree_index_(ScrollTree::kInvalidNodeId),
property_tree_sequence_number_(-1),
- should_flatten_transform_from_property_tree_(false),
+ should_flatten_screen_space_transform_from_property_tree_(false),
draws_content_(false),
should_check_backface_visibility_(false),
cache_render_surface_(false),
@@ -95,8 +95,7 @@ Layer::Layer()
needs_show_scrollbars_(false),
has_transform_node_(false),
subtree_has_copy_request_(false),
- safe_opaque_background_color_(0),
- num_unclipped_descendants_(0) {}
+ safe_opaque_background_color_(0) {}
Layer::~Layer() {
// Our parent should be holding a reference to us so there should be no
@@ -150,7 +149,7 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) {
inputs_.mask_layer->SetLayerTreeHost(host);
if (host && !host->IsUsingLayerLists() &&
- GetMutatorHost()->IsElementAnimating(element_id())) {
+ host->mutator_host()->IsElementAnimating(element_id())) {
host->SetNeedsCommit();
}
}
@@ -186,11 +185,6 @@ void Layer::SetNeedsPushProperties() {
layer_tree_host_->AddLayerShouldPushProperties(this);
}
-void Layer::ResetNeedsPushPropertiesForTesting() {
- if (layer_tree_host_)
- layer_tree_host_->RemoveLayerShouldPushProperties(this);
-}
-
bool Layer::IsPropertyChangeAllowed() const {
if (!layer_tree_host_)
return true;
@@ -361,16 +355,6 @@ void Layer::RemoveAllChildren() {
}
}
-void Layer::SetChildren(const LayerList& children) {
- DCHECK(IsPropertyChangeAllowed());
- if (children == inputs_.children)
- return;
-
- RemoveAllChildren();
- for (size_t i = 0; i < children.size(); ++i)
- AddChild(children[i]);
-}
-
bool Layer::HasAncestor(const Layer* ancestor) const {
for (const Layer* layer = parent(); layer; layer = layer->parent()) {
if (layer == ancestor)
@@ -423,9 +407,10 @@ void Layer::SetBackgroundColor(SkColor background_color) {
void Layer::SetSafeOpaqueBackgroundColor(SkColor background_color) {
DCHECK(IsPropertyChangeAllowed());
- if (safe_opaque_background_color_ == background_color)
+ SkColor opaque_color = SkColorSetA(background_color, 255);
+ if (safe_opaque_background_color_ == opaque_color)
return;
- safe_opaque_background_color_ = background_color;
+ safe_opaque_background_color_ = opaque_color;
SetNeedsPushProperties();
}
@@ -448,7 +433,7 @@ void Layer::SetMasksToBounds(bool masks_to_bounds) {
SetSubtreePropertyChanged();
}
-void Layer::SetMaskLayer(Layer* mask_layer) {
+void Layer::SetMaskLayer(PictureLayer* mask_layer) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.mask_layer.get() == mask_layer)
return;
@@ -644,8 +629,10 @@ void Layer::SetPosition(const gfx::PointF& position) {
return;
SetSubtreePropertyChanged();
- TransformNode* transform_node = GetTransformNode();
- if (transform_node) {
+ if (has_transform_node_) {
+ TransformNode* transform_node =
+ layer_tree_host_->property_trees()->transform_tree.Node(
+ transform_tree_index_);
transform_node->update_post_local_transform(position, transform_origin());
transform_node->needs_local_transform_update = true;
transform_node->transform_changed = true;
@@ -684,23 +671,21 @@ void Layer::SetTransform(const gfx::Transform& transform) {
SetSubtreePropertyChanged();
if (layer_tree_host_) {
if (has_transform_node_) {
- PropertyTrees* property_trees = layer_tree_host_->property_trees();
- if (TransformNode* transform_node =
- property_trees->transform_tree.Node(transform_tree_index())) {
- // We need to trigger a rebuild if we could have affected 2d axis
- // alignment. We'll check to see if transform and inputs_.transform are
- // axis align with respect to one another.
- DCHECK_EQ(transform_tree_index(), transform_node->id);
- bool preserves_2d_axis_alignment =
- Are2dAxisAligned(inputs_.transform, transform);
- transform_node->local = transform;
- transform_node->needs_local_transform_update = true;
- transform_node->transform_changed = true;
- layer_tree_host_->property_trees()->transform_tree.set_needs_update(
- true);
- if (!preserves_2d_axis_alignment)
- SetPropertyTreesNeedRebuild();
- }
+ TransformNode* transform_node =
+ layer_tree_host_->property_trees()->transform_tree.Node(
+ transform_tree_index_);
+ // We need to trigger a rebuild if we could have affected 2d axis
+ // alignment. We'll check to see if transform and inputs_.transform are
+ // axis align with respect to one another.
+ DCHECK_EQ(transform_tree_index(), transform_node->id);
+ bool preserves_2d_axis_alignment =
+ Are2dAxisAligned(inputs_.transform, transform);
+ transform_node->local = transform;
+ transform_node->needs_local_transform_update = true;
+ transform_node->transform_changed = true;
+ layer_tree_host_->property_trees()->transform_tree.set_needs_update(true);
+ if (!preserves_2d_axis_alignment)
+ SetPropertyTreesNeedRebuild();
} else {
SetPropertyTreesNeedRebuild();
}
@@ -720,8 +705,10 @@ void Layer::SetTransformOrigin(const gfx::Point3F& transform_origin) {
return;
SetSubtreePropertyChanged();
- TransformNode* transform_node = GetTransformNode();
- if (transform_node) {
+ if (has_transform_node_) {
+ TransformNode* transform_node =
+ layer_tree_host_->property_trees()->transform_tree.Node(
+ transform_tree_index_);
DCHECK_EQ(transform_tree_index(), transform_node->id);
transform_node->update_pre_local_transform(transform_origin);
transform_node->update_post_local_transform(position(), transform_origin);
@@ -735,10 +722,6 @@ void Layer::SetTransformOrigin(const gfx::Point3F& transform_origin) {
SetNeedsCommit();
}
-bool Layer::ScrollOffsetAnimationWasInterrupted() const {
- return GetMutatorHost()->ScrollOffsetAnimationWasInterrupted(element_id());
-}
-
void Layer::SetScrollParent(Layer* parent) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.scroll_parent == parent)
@@ -1039,6 +1022,13 @@ int Layer::scroll_tree_index() const {
return scroll_tree_index_;
}
+void Layer::SetOffsetToTransformParent(gfx::Vector2dF offset) {
+ if (offset_to_transform_parent_ == offset)
+ return;
+ offset_to_transform_parent_ = offset;
+ SetNeedsPushProperties();
+}
+
void Layer::InvalidatePropertyTreesIndices() {
SetTransformTreeIndex(TransformTree::kInvalidNodeId);
SetClipTreeIndex(ClipTree::kInvalidNodeId);
@@ -1168,8 +1158,8 @@ void Layer::SetLayerClient(base::WeakPtr<LayerClient> client) {
inputs_.debug_info = nullptr;
}
-bool Layer::IsSnapped() {
- return scrollable();
+bool Layer::IsSnappedToPixelGridInTarget() {
+ return false;
}
void Layer::PushPropertiesTo(LayerImpl* layer) {
@@ -1189,7 +1179,7 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetEffectTreeIndex(effect_tree_index());
layer->SetClipTreeIndex(clip_tree_index());
layer->SetScrollTreeIndex(scroll_tree_index());
- layer->set_offset_to_transform_parent(offset_to_transform_parent_);
+ layer->SetOffsetToTransformParent(offset_to_transform_parent_);
layer->SetDrawsContent(DrawsContent());
layer->SetHitTestableWithoutDrawsContent(
hit_testable_without_draws_content());
@@ -1203,10 +1193,22 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
inputs_.main_thread_scrolling_reasons);
layer->SetNonFastScrollableRegion(inputs_.non_fast_scrollable_region);
layer->SetTouchActionRegion(inputs_.touch_action_region);
+ // TODO(sunxd): Pass the correct region for wheel event handlers, see
+ // https://crbug.com/841364.
+ if (layer_tree_host()->event_listener_properties(
+ EventListenerClass::kMouseWheel) ==
+ EventListenerProperties::kBlocking ||
+ layer_tree_host()->event_listener_properties(
+ EventListenerClass::kMouseWheel) ==
+ EventListenerProperties::kBlockingAndPassive) {
+ layer->SetWheelEventHandlerRegion(Region(gfx::Rect(bounds())));
+ } else {
+ layer->SetWheelEventHandlerRegion(Region());
+ }
layer->SetContentsOpaque(inputs_.contents_opaque);
layer->SetPosition(inputs_.position);
- layer->set_should_flatten_transform_from_property_tree(
- should_flatten_transform_from_property_tree_);
+ layer->SetShouldFlattenScreenSpaceTransformFromPropertyTree(
+ should_flatten_screen_space_transform_from_property_tree_);
layer->SetUseParentBackfaceVisibility(inputs_.use_parent_backface_visibility);
layer->SetShouldCheckBackfaceVisibility(should_check_backface_visibility_);
@@ -1221,10 +1223,11 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
// the pending tree will clobber any impl-side scrolling occuring on the
// active tree. To do so, avoid scrolling the pending tree along with it
// instead of trying to undo that scrolling later.
- if (ScrollOffsetAnimationWasInterrupted())
- layer->layer_tree_impl()
- ->property_trees()
- ->scroll_tree.SetScrollOffsetClobberActiveValue(layer->element_id());
+ if (layer_tree_host_->mutator_host()->ScrollOffsetAnimationWasInterrupted(
+ element_id())) {
+ PropertyTrees* trees = layer->layer_tree_impl()->property_trees();
+ trees->scroll_tree.SetScrollOffsetClobberActiveValue(layer->element_id());
+ }
if (needs_show_scrollbars_)
layer->set_needs_show_scrollbars(true);
@@ -1239,8 +1242,6 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetHasWillChangeTransformHint(has_will_change_transform_hint());
layer->SetNeedsPushProperties();
- layer->SetTrilinearFiltering(trilinear_filtering());
-
// Reset any state that should be cleared for the next update.
needs_show_scrollbars_ = false;
subtree_property_changed_ = false;
@@ -1326,6 +1327,15 @@ void Layer::SetSubtreePropertyChanged() {
SetNeedsPushProperties();
}
+void Layer::SetShouldFlattenScreenSpaceTransformFromPropertyTree(
+ bool should_flatten) {
+ if (should_flatten_screen_space_transform_from_property_tree_ ==
+ should_flatten)
+ return;
+ should_flatten_screen_space_transform_from_property_tree_ = should_flatten;
+ SetNeedsPushProperties();
+}
+
void Layer::SetMayContainVideo(bool yes) {
if (may_contain_video_ == yes)
return;
@@ -1350,23 +1360,10 @@ void Layer::OnOpacityAnimated(float opacity) {
inputs_.opacity = opacity;
}
-TransformNode* Layer::GetTransformNode() const {
- return has_transform_node_
- ? layer_tree_host_->property_trees()->transform_tree.Node(
- transform_tree_index_)
- : nullptr;
-}
-
void Layer::OnTransformAnimated(const gfx::Transform& transform) {
inputs_.transform = transform;
}
-bool Layer::HasTickingAnimationForTesting() const {
- return layer_tree_host_
- ? GetMutatorHost()->HasTickingKeyframeModelForTesting(element_id())
- : false;
-}
-
void Layer::SetHasWillChangeTransformHint(bool has_will_change) {
if (inputs_.has_will_change_transform_hint == has_will_change)
return;
@@ -1378,21 +1375,18 @@ void Layer::SetTrilinearFiltering(bool trilinear_filtering) {
if (inputs_.trilinear_filtering == trilinear_filtering)
return;
inputs_.trilinear_filtering = trilinear_filtering;
+ // When true, makes a RenderSurface which makes an effect node.
+ SetPropertyTreesNeedRebuild();
+ // Adding a RenderSurface may change how things in the subtree appear, since
+ // it flattens transforms.
+ SetSubtreePropertyChanged();
SetNeedsCommit();
}
-MutatorHost* Layer::GetMutatorHost() const {
- return layer_tree_host_ ? layer_tree_host_->mutator_host() : nullptr;
-}
-
ElementListType Layer::GetElementTypeForAnimation() const {
return ElementListType::ACTIVE;
}
-ScrollbarLayerInterface* Layer::ToScrollbarLayer() {
- return nullptr;
-}
-
void Layer::RemoveFromClipTree() {
if (clip_children_.get()) {
std::set<Layer*> copy = *clip_children_;
@@ -1415,9 +1409,7 @@ void Layer::AddDrawableDescendants(int num) {
parent()->AddDrawableDescendants(num);
}
-void Layer::RunMicroBenchmark(MicroBenchmark* benchmark) {
- benchmark->RunOnLayer(this);
-}
+void Layer::RunMicroBenchmark(MicroBenchmark* benchmark) {}
void Layer::SetElementId(ElementId id) {
DCHECK(IsPropertyChangeAllowed());
@@ -1441,12 +1433,6 @@ void Layer::SetElementId(ElementId id) {
SetNeedsCommit();
}
-bool Layer::has_copy_requests_in_target_subtree() {
- return layer_tree_host_->property_trees()
- ->effect_tree.Node(effect_tree_index())
- ->subtree_has_copy_request;
-}
-
gfx::Transform Layer::ScreenSpaceTransform() const {
DCHECK_NE(transform_tree_index_, TransformTree::kInvalidNodeId);
return draw_property_utils::ScreenSpaceTransform(
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index 32f87b182cd..ff1e60cce3d 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -29,7 +29,6 @@
#include "cc/paint/filter_operations.h"
#include "cc/paint/paint_record.h"
#include "cc/trees/element_id.h"
-#include "cc/trees/mutator_host_client.h"
#include "cc/trees/property_tree.h"
#include "cc/trees/target_property.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -56,42 +55,80 @@ class LayerImpl;
class LayerTreeHost;
class LayerTreeHostCommon;
class LayerTreeImpl;
-class MutatorHost;
-class ScrollbarLayerInterface;
+class PictureLayer;
// Base class for composited layers. Special layer types are derived from
-// this class.
+// this class. Each layer is an independent unit in the compositor, be that
+// for transforming or for content. If a layer has content it can be
+// transformed efficiently without requiring the content to be recreated.
+// Layers form a tree, with each layer having 0 or more children, and a single
+// parent (or none at the root). Layers within the tree, other than the root
+// layer, are kept alive by that tree relationship, with refpointer ownership
+// from parents to children.
class CC_EXPORT Layer : public base::RefCounted<Layer> {
public:
using LayerListType = LayerList;
+ // An invalid layer id, as all layer ids are positive.
enum LayerIdLabels {
INVALID_ID = -1,
};
+ // A layer can be attached to another layer as a mask for it. These
+ // describe how the mask would be generated as a texture in that case.
enum LayerMaskType {
NOT_MASK = 0,
MULTI_TEXTURE_MASK,
SINGLE_TEXTURE_MASK,
};
+ // Factory to create a new Layer, with a unique id.
static scoped_refptr<Layer> Create();
+ // Sets an optional client on this layer, that will be called when relevant
+ // events happen. The client is a WeakPtr so it can be destroyed without
+ // unsetting itself as the client.
+ void SetLayerClient(base::WeakPtr<LayerClient> client);
+ LayerClient* GetLayerClientForTesting() const { return inputs_.client.get(); }
+
+ // A unique and stable id for the Layer. Ids are always positive.
int id() const { return inputs_.layer_id; }
+ // Returns a pointer to the highest ancestor of this layer, or itself.
Layer* RootLayer();
+ // Returns a pointer to the direct ancestor of this layer if it exists,
+ // or null.
Layer* parent() { return parent_; }
const Layer* parent() const { return parent_; }
+ // Appends |child| to the list of children of this layer, and maintains
+ // ownership of a reference to that |child|.
void AddChild(scoped_refptr<Layer> child);
+ // Inserts |child| into the list of children of this layer, before position
+ // |index| (0 based) and maintains ownership of a reference to that |child|.
void InsertChild(scoped_refptr<Layer> child, size_t index);
+ // Removes an existing child |reference| from this layer's list of children,
+ // and inserts |new_layer| it its place in the list. This layer maintains
+ // ownership of a reference to the |new_layer|. The |new_layer| may be null,
+ // in which case |reference| is simply removed from the list of children,
+ // which ends this layers ownership of the child.
void ReplaceChild(Layer* reference, scoped_refptr<Layer> new_layer);
+ // Removes this layer from the list of children in its parent, removing the
+ // parent's ownership of this layer.
void RemoveFromParent();
+ // Removes all children from this layer's list of children, removing ownership
+ // of those children.
void RemoveAllChildren();
- void SetChildren(const LayerList& children);
+ // Returns true if |ancestor| is this layer's parent or higher ancestor.
bool HasAncestor(const Layer* ancestor) const;
+ // The list of children of this layer.
const LayerList& children() const { return inputs_.children; }
- Layer* child_at(size_t index) { return inputs_.children[index].get(); }
+
+ // Gets the LayerTreeHost that this layer is attached to, or null if not.
+ // A layer is attached to a LayerTreeHost if it or an ancestor layer is set as
+ // the root layer of a LayerTreeHost (while noting only a layer without a
+ // parent may be set as the root layer).
+ LayerTreeHost* layer_tree_host() const { return layer_tree_host_; }
// This requests the layer and its subtree be rendered and given to the
// callback. If the copy is unable to be produced (the layer is destroyed
@@ -99,57 +136,114 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// request's source property is set, any prior uncommitted requests having the
// same source will be aborted.
void RequestCopyOfOutput(std::unique_ptr<viz::CopyOutputRequest> request);
+ // True if a copy request has been inserted on this layer and a commit has not
+ // occured yet.
bool HasCopyRequest() const { return !inputs_.copy_requests.empty(); }
- void SetSubtreeHasCopyRequest(bool subtree_has_copy_request);
- bool SubtreeHasCopyRequest() const;
-
- void TakeCopyRequests(
- std::vector<std::unique_ptr<viz::CopyOutputRequest>>* requests);
-
+ // Set and get the background color for the layer. This color is not used by
+ // basic Layers, but subclasses may make use of it.
virtual void SetBackgroundColor(SkColor background_color);
SkColor background_color() const { return inputs_.background_color; }
+
+ // Internal to property tree generation. Sets an opaque background color for
+ // the layer, to be used in place of the background_color() if the layer says
+ // contents_opaque() is true.
void SetSafeOpaqueBackgroundColor(SkColor background_color);
- // If contents_opaque(), return an opaque color else return a
- // non-opaque color. Tries to return background_color(), if possible.
+ // Returns a background color with opaque-ness equal to the value of
+ // contents_opaque().
+ // If the layer says contents_opaque() is true, this returns the value set by
+ // SetSafeOpaqueBackgroundColor() which should be an opaque color. Otherwise,
+ // it returns something non-opaque. It prefers to return the
+ // background_color(), but if the background_color() is opaque (and this layer
+ // claims to not be), then SK_ColorTRANSPARENT is returned.
SkColor SafeOpaqueBackgroundColor() const;
- // A layer's bounds are in logical, non-page-scaled pixels (however, the
- // root layer's bounds are in physical pixels).
+ // Set and get the position of this layer, relative to its parent. This is
+ // specified in layer space, which excludes device scale and page scale
+ // factors, and ignoring transforms for this layer or ancestor layers. The
+ // root layer's position is not used as it always appears at the origin of
+ // the viewport.
+ void SetPosition(const gfx::PointF& position);
+ const gfx::PointF& position() const { return inputs_.position; }
+
+ // Set and get the layers bounds. This is specified in layer space, which
+ // excludes device scale and page scale factors, and ignoring transforms for
+ // this layer or ancestor layers.
+ //
+ // The root layer in the tree has bounds in viewport space, which includes
+ // the device scale factor.
void SetBounds(const gfx::Size& bounds);
const gfx::Size& bounds() const { return inputs_.bounds; }
+ // Set and get the behaviour to be applied for compositor-thread scrolling of
+ // this layer beyond the beginning or end of the layer's content.
void SetOverscrollBehavior(const OverscrollBehavior& behavior);
OverscrollBehavior overscroll_behavior() const {
return inputs_.overscroll_behavior;
}
+ // Set and get the snapping behaviour for compositor-thread scrolling of
+ // this layer. The default value of null means there is no snapping for the
+ // layer.
void SetSnapContainerData(base::Optional<SnapContainerData> data);
const base::Optional<SnapContainerData>& snap_container_data() const {
return inputs_.snap_container_data;
}
+ // Set or get that this layer clips its subtree to within its bounds. Content
+ // of children will be intersected with the bounds of this layer when true.
void SetMasksToBounds(bool masks_to_bounds);
bool masks_to_bounds() const { return inputs_.masks_to_bounds; }
- void SetMaskLayer(Layer* mask_layer);
- Layer* mask_layer() { return inputs_.mask_layer.get(); }
- const Layer* mask_layer() const { return inputs_.mask_layer.get(); }
+ // 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.
+ void SetClipParent(Layer* ancestor);
+ Layer* clip_parent() { return inputs_.clip_parent; }
+
+ // The set of layers which are not in this layers subtree but which should be
+ // clipped to only appear within this layer's bounds.
+ std::set<Layer*>* clip_children() { return clip_children_.get(); }
+ const std::set<Layer*>* clip_children() const { return clip_children_.get(); }
+
+ // Set or get a layer that will mask the contents of this layer. The alpha
+ // channel of the mask layer's content is used as an alpha mask of this
+ // layer's content. IOW the mask's alpha is multiplied by this layer's alpha
+ // for each matching pixel.
+ void SetMaskLayer(PictureLayer* mask_layer);
+ PictureLayer* mask_layer() { return inputs_.mask_layer.get(); }
+ const PictureLayer* mask_layer() const { return inputs_.mask_layer.get(); }
// Marks the |dirty_rect| as being changed, which will cause a commit and
// the compositor to submit a new frame with a damage rect that includes the
- // layer's dirty area.
+ // layer's dirty area. This rect is in layer space, the same as bounds().
virtual void SetNeedsDisplayRect(const gfx::Rect& dirty_rect);
// Marks the entire layer's bounds as being changed, which will cause a commit
// and the compositor to submit a new frame with a damage rect that includes
- // the entire layer.
+ // the entire layer. Note that if the layer resizes afterward, but before
+ // commit, the dirty rect would not cover the layer, however then the layer
+ // bounds change would implicitly damage the full layer.
void SetNeedsDisplay() { SetNeedsDisplayRect(gfx::Rect(bounds())); }
+ // Returns the union of previous calls to SetNeedsDisplayRect() and
+ // SetNeedsDisplay() that have not been committed to the compositor thread.
+ const gfx::Rect& update_rect() const { return inputs_.update_rect; }
+ // Set or get the opacity which should be applied to the contents of the layer
+ // and its subtree (together as a single composited entity) when blending them
+ // into their target. Note that this does not speak to the contents of this
+ // layer, which may be opaque or not (see contents_opaque()). Note that the
+ // opacity is cumulative since it applies to the layer's subtree.
virtual void SetOpacity(float opacity);
float opacity() const { return inputs_.opacity; }
+ // Gets the true opacity that will be used for blending the contents of this
+ // layer and its subtree into its target during composite. This value is the
+ // same as the user-specified opacity() unless the layer should not be visible
+ // at all for other reasons, in which case the opacity here becomes 0.
float EffectiveOpacity() const;
- virtual bool OpacityCanAnimateOnImplThread() const;
+ // Set or get the blend mode to be applied when blending the contents of the
+ // layer and its subtree (together as a single composited entity) when
+ // blending them into their target.
void SetBlendMode(SkBlendMode blend_mode);
SkBlendMode blend_mode() const { return inputs_.blend_mode; }
@@ -162,97 +256,149 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
return inputs_.is_root_for_isolated_group;
}
- // Make the layer hit testable even if |draws_content_| is false.
- void SetHitTestableWithoutDrawsContent(bool should_hit_test);
- bool hit_testable_without_draws_content() const {
- return inputs_.hit_testable_without_draws_content;
- }
-
+ // Set or get the list of filter effects to be applied to the contents of the
+ // layer and its subtree (together as a single composited entity) when
+ // drawing them into their target.
void SetFilters(const FilterOperations& filters);
const FilterOperations& filters() const { return inputs_.filters; }
- // Background filters are filters applied to what is behind this layer, when
- // they are viewed through non-opaque regions in this layer.
+ // Set or get the origin to be used when applying the filters given to
+ // SetFilters(). By default the origin is at the origin of this layer, but
+ // may be moved positively or negatively relative to that. The origin effects
+ // any filters which do not apply uniformly to the entire layer and its
+ // subtree.
+ void SetFiltersOrigin(const gfx::PointF& origin);
+ gfx::PointF filters_origin() const { return inputs_.filters_origin; }
+
+ // Set or get the list of filters that should be applied to the content this
+ // layer and its subtree will be drawn into. The effect is clipped to only
+ // apply directly behind this layer and its subtree.
void SetBackgroundFilters(const FilterOperations& filters);
const FilterOperations& background_filters() const {
return inputs_.background_filters;
}
+ // Set or get an optimization hint that the contents of this layer are fully
+ // opaque or not. If true, every pixel of content inside the layer's bounds
+ // must be opaque or visual errors can occur. This applies only to this layer
+ // and not to children, and does not imply the layer should be composited
+ // opaquely, as effects may be applied such as opacity() or filters().
void SetContentsOpaque(bool opaque);
bool contents_opaque() const { return inputs_.contents_opaque; }
- void SetPosition(const gfx::PointF& position);
- const gfx::PointF& position() const { return inputs_.position; }
+ // Set or get whether this layer should be a hit test target even if not
+ // visible. Normally if DrawsContent() is false, making the layer not
+ // contribute to the final composited output, the layer will not be eligable
+ // for hit testing since it is invisible. Set this to true to allow the layer
+ // to be hit tested regardless.
+ void SetHitTestableWithoutDrawsContent(bool should_hit_test);
+ bool hit_testable_without_draws_content() const {
+ return inputs_.hit_testable_without_draws_content;
+ }
+ // Set or gets if this layer is a container for fixed position layers in its
+ // subtree. Such layers will be positioned and transformed relative to this
+ // layer instead of their direct parent.
+ //
// A layer that is a container for fixed position layers cannot be both
// scrollable and have a non-identity transform.
void SetIsContainerForFixedPositionLayers(bool container);
bool IsContainerForFixedPositionLayers() const;
- void SetIsResizedByBrowserControls(bool resized);
- bool IsResizedByBrowserControls() const;
-
+ // Set or get constraints applied to the layer's position, where it may be
+ // in a fixed position relative to the nearest ancestor that returns true for
+ // IsContainerForFixedPositionLayers(). This may also specify which edges
+ // of the layer are fixed to the same edges of the container ancestor. When
+ // fixed position, this layer's transform will be appended to the container
+ // ancestor's transform instead of to this layer's direct parent's.
void SetPositionConstraint(const LayerPositionConstraint& constraint);
const LayerPositionConstraint& position_constraint() const {
return inputs_.position_constraint;
}
+ // Set or get constraints applied to the layer's position, where it may act
+ // like a normal layer until, during scroll, its position triggers it to
+ // become fixed position relative to its scroller. See CSS position: sticky
+ // for more details.
void SetStickyPositionConstraint(
const LayerStickyPositionConstraint& constraint);
const LayerStickyPositionConstraint& sticky_position_constraint() const {
return inputs_.sticky_position_constraint;
}
- TransformNode* GetTransformNode() const;
+ // On some platforms (Android renderer) the viewport may resize during scroll
+ // on the compositor thread. During this resize and until the main thread
+ // matches, position fixed layers may need to have their position adjusted on
+ // the compositor thread to keep them fixed in place. If
+ // IsContainerForFixedPositionLayers() is true for this layer, these set and
+ // get whether fixed position descendants of this layer should have this
+ // adjustment to their position applied during such a viewport resize.
+ void SetIsResizedByBrowserControls(bool resized);
+ bool IsResizedByBrowserControls() const;
+ // Set or get the transform to be used when compositing this layer into its
+ // target. The transform is inherited by this layers children.
void SetTransform(const gfx::Transform& transform);
const gfx::Transform& transform() const { return inputs_.transform; }
+ // Gets the transform, including transform origin and position, of this layer
+ // and its ancestors, device scale and page scale factors, into the device
+ // viewport.
+ gfx::Transform ScreenSpaceTransform() const;
+
+ // Set or get the origin to be used when applying the transform. The value is
+ // a position in layer space, relative to the top left corner of this layer.
+ // For instance, if set to the center of the layer, with a transform to rotate
+ // 180deg around the X axis, it would flip the layer vertically around the
+ // center of the layer, leaving it occupying the same space. Whereas set to
+ // the top left of the layer, the rotation wouldoccur around the top of the
+ // layer, moving it vertically while flipping it.
void SetTransformOrigin(const gfx::Point3F&);
const gfx::Point3F& transform_origin() const {
return inputs_.transform_origin;
}
+ // Set or get a scroll parent layer. It is not an ancestor of this layer, but
+ // this layer will be moved by the scroll parent's scroll offset.
void SetScrollParent(Layer* parent);
-
Layer* scroll_parent() { return inputs_.scroll_parent; }
- void SetClipParent(Layer* ancestor);
-
- Layer* clip_parent() { return inputs_.clip_parent; }
-
- std::set<Layer*>* clip_children() { return clip_children_.get(); }
- const std::set<Layer*>* clip_children() const {
- return clip_children_.get();
- }
-
- gfx::Transform ScreenSpaceTransform() const;
-
- void set_num_unclipped_descendants(size_t descendants) {
- num_unclipped_descendants_ = descendants;
- }
- size_t num_unclipped_descendants() const {
- return num_unclipped_descendants_;
- }
-
+ // Set or get the scroll offset of the layer. The content of the layer, and
+ // position of its subtree, as well as other layers for which this layer is
+ // their scroll parent, and their subtrees) is moved up by the amount of
+ // offset specified here.
void SetScrollOffset(const gfx::ScrollOffset& scroll_offset);
-
- const gfx::ScrollOffset& scroll_offset() const {
+ // Accessor named to match LayerImpl for templated code.
+ const gfx::ScrollOffset& CurrentScrollOffset() const {
return inputs_.scroll_offset;
}
+
// Called internally during commit to update the layer with state from the
// compositor thread. Not to be called externally by users of this class.
void SetScrollOffsetFromImplSide(const gfx::ScrollOffset& scroll_offset);
- // Marks this layer as being scrollable and needing an associated scroll node.
- // The scroll node's bounds and container_bounds will be kept in sync
- // with this layer. Once scrollable, a Layer cannot become un-scrollable.
+ // Marks this layer as being scrollable and needing an associated scroll node,
+ // and specifies the total size of the content to be scrolled (ie the max
+ // scroll offsets. The size should be a union of the layer and its subtree, as
+ // well as any layers for whom this layer is their scroll parent, and their
+ // subtrees, when they are transformed into this layer's space. Thus
+ // transforms of children affect the size of the |scroll_container_bounds|.
+ // Once scrollable, a Layer cannot become un-scrollable.
void SetScrollable(const gfx::Size& scroll_container_bounds);
+ bool scrollable() const { return inputs_.scrollable; }
const gfx::Size& scroll_container_bounds() const {
return inputs_.scroll_container_bounds;
}
- bool scrollable() const { return inputs_.scrollable; }
+ // Set or get if this layer is able to be scrolled along each axis. These are
+ // independant of the scrollable state, or size of the scrollable area
+ // specified in SetScrollable(), as these may be enabled or disabled
+ // dynamically, while SetScrollable() defines what would be possible if these
+ // are enabled.
+ // When disabled, overscroll elasticity will not be used if the scroll offset
+ // ends up past the maximum range. And when enabled, with overlay scrollbars,
+ // the scrollbars will be shown when the scroll offset changes if these are
+ // set to true.
void SetUserScrollable(bool horizontal, bool vertical);
bool user_scrollable_horizontal() const {
return inputs_.user_scrollable_horizontal;
@@ -261,65 +407,118 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
return inputs_.user_scrollable_vertical;
}
+ // Set or get if this layer is able to be scrolled on the compositor thread.
+ // This only applies for layers that are marked as scrollable, not for layers
+ // that are moved by a scroll parent. When any reason is present, the layer
+ // will not be scrolled on the compositor thread. The reasons are a set of
+ // bitflags from MainThreadScrollingReason, used to track the reason for
+ // debugging and reporting.
+ // AddMainThreadScrollingReasons() is used to add flags to the current set,
+ // and ClearMainThreadScrollingReasons() removes flags from the current set.
void AddMainThreadScrollingReasons(uint32_t main_thread_scrolling_reasons);
void ClearMainThreadScrollingReasons(
uint32_t main_thread_scrolling_reasons_to_clear);
uint32_t main_thread_scrolling_reasons() const {
return inputs_.main_thread_scrolling_reasons;
}
- bool should_scroll_on_main_thread() const {
- return !!inputs_.main_thread_scrolling_reasons;
- }
+ // Set or get an area of this layer within which initiating a scroll can not
+ // be done from the compositor thread. Within this area, if the user attempts
+ // to start a scroll, the events must be sent to the main thread and processed
+ // there.
void SetNonFastScrollableRegion(const Region& non_fast_scrollable_region);
const Region& non_fast_scrollable_region() const {
return inputs_.non_fast_scrollable_region;
}
+ // Set or get the set of touch actions allowed across each point of this
+ // layer. The |touch_action_region| can specify, for any number of areas,
+ // which touch actions are allowed in each area. The result is the
+ // intersection of overlapping areas. These allowed actions control if
+ // a touch event can initiate a scroll or zoom on the compositor thread.
void SetTouchActionRegion(TouchActionRegion touch_action_region);
const TouchActionRegion& touch_action_region() const {
return inputs_.touch_action_region;
}
+ // Sets a RepeatingCallback that is run during a main frame, before layers are
+ // asked to prepare content with Update(), if the scroll offset for the layer
+ // was changed by the InputHandlerClient, on the compositor thread (or on the
+ // main thread in single-thread mode). It may be set to a null callback, in
+ // which case nothing is called.
void set_did_scroll_callback(
- base::Callback<void(const gfx::ScrollOffset&, const ElementId&)>
+ base::RepeatingCallback<void(const gfx::ScrollOffset&, const ElementId&)>
callback) {
inputs_.did_scroll_callback = std::move(callback);
}
+ // Set or get if the layer and its subtree should be cached as a texture in
+ // the display compositor. This is used as an optimization when it is known
+ // that the layer will be animated without changing its content, or any of its
+ // subtree.
+ //
+ // Note that this also disables occlusion culling, as the entire texture will
+ // be drawn so that it is not left with incomplete areas. This should only be
+ // used when paying the cost of creating an intermediate texture is worth it,
+ // even when the layer's subtree may be occluded, or not visible in the final
+ // output.
void SetCacheRenderSurface(bool cache_render_surface);
bool cache_render_surface() const { return cache_render_surface_; }
+ // 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
+ // without needing to set up such effects.
void SetForceRenderSurfaceForTesting(bool force_render_surface);
bool force_render_surface_for_testing() const {
return force_render_surface_for_testing_;
}
- const gfx::ScrollOffset& CurrentScrollOffset() const {
- return inputs_.scroll_offset;
- }
-
+ // Set or get if this layer should continue to be visible when rotated such
+ // that its back face is facing toward the camera. If false, the layer will
+ // disappear when its back face is visible, but if true, the mirror image of
+ // its front face will be shown. For instance, with a 180deg rotation around
+ // the middle of the layer on the Y axis, if this is false then nothing is
+ // visible. But if true, the layer is seen with its contents flipped along the
+ // Y axis. Being single-sided applies transitively to the subtree of this
+ // layer. If it is hidden because of its back face being visible, then its
+ // subtree will be too (even if a subtree layer's front face would have been
+ // visible).
+ //
+ // Note that should_check_backface_visibility() is the final computed value
+ // for back face visibility, which is only for internal use.
void SetDoubleSided(bool double_sided);
bool double_sided() const { return inputs_.double_sided; }
- void SetShouldFlattenTransform(bool flatten);
- bool should_flatten_transform() const {
- return inputs_.should_flatten_transform;
- }
-
- bool Is3dSorted() const { return inputs_.sorting_context_id != 0; }
-
+ // Set or get if SetDoubleSided() for this layer should be ignored and
+ // inherited directly from this layer's parent instead. Used to attach this
+ // layer's backface visibility to the value of its parent.
+ //
+ // Note that should_check_backface_visibility() is the final computed value
+ // for back face visibility, which is only for internal use.
void SetUseParentBackfaceVisibility(bool use);
bool use_parent_backface_visibility() const {
return inputs_.use_parent_backface_visibility;
}
- void SetShouldCheckBackfaceVisibility(bool should_check_backface_visibility);
- bool should_check_backface_visibility() const {
- return should_check_backface_visibility_;
+ // Set or get if the subtree of this layer is composited in 3d-space, or if
+ // the layers are flattened into the plane of this layer. This supports the
+ // transform-style CSS property.
+ void SetShouldFlattenTransform(bool flatten);
+ bool should_flatten_transform() const {
+ return inputs_.should_flatten_transform;
}
- virtual void SetLayerTreeHost(LayerTreeHost* host);
+ // Set or get a 3d sorting context for this layer, where adjacent layers (in a
+ // pre-order traversal) with the same id are sorted as a group and may occlude
+ // each other based on their z-position, including intersecting each other and
+ // each occluding the other layer partially. Layers in different sorting
+ // contexts will be composited and occlude in tree order (children occlude
+ // ancestors and earlier siblings in the children list). If the |id| is 0,
+ // then the layer is not part of any sorting context, and is always composited
+ // in tree order.
+ void Set3dSortingContextId(int id);
+ int sorting_context_id() const { return inputs_.sorting_context_id; }
// When true the layer may contribute to the compositor's output. When false,
// it does not. This property does not apply to children of the layer, they
@@ -327,61 +526,162 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// if it has content to contribute, but when false, this prevents it from
// doing so.
void SetIsDrawable(bool is_drawable);
-
- void SetHideLayerAndSubtree(bool hide);
- bool hide_layer_and_subtree() const { return inputs_.hide_layer_and_subtree; }
-
- void SetFiltersOrigin(const gfx::PointF& origin);
- gfx::PointF filters_origin() const { return inputs_.filters_origin; }
-
- int NumDescendantsThatDrawContent() const;
-
// Is true if the layer will contribute content to the compositor's output.
// Will be false if SetIsDrawable(false) is called. But will also be false if
// the layer itself has no content to contribute, even though the layer was
// given SetIsDrawable(true).
- // This is only virtual for tests.
- // TODO(awoloszyn): Remove this once we no longer need it for tests
- virtual bool DrawsContent() const;
+ bool DrawsContent() const;
- // This methods typically need to be overwritten by derived classes.
- // Returns true iff anything was updated that needs to be committed.
- virtual bool Update();
- virtual void SetLayerMaskType(Layer::LayerMaskType type) {}
- virtual bool HasSlowPaths() const;
- virtual bool HasNonAAPaint() const;
+ // Returns the number of layers in this layers subtree (excluding itself) for
+ // which DrawsContent() is true.
+ int NumDescendantsThatDrawContent() const;
- void UpdateDebugInfo();
+ // Set or get if this layer and its subtree should be part of the compositor's
+ // output to the screen. When set to true, the layer's subtree does not appear
+ // to the user, but still remains part of the tree with all its normal drawing
+ // properties. This can be used to execute a CopyOutputRequest on this layer
+ // or another in its subtree, since the layers are still able to be drawn by
+ // the compositor, while not being composed into the result shown to the user.
+ void SetHideLayerAndSubtree(bool hide);
+ bool hide_layer_and_subtree() const { return inputs_.hide_layer_and_subtree; }
- void SetLayerClient(base::WeakPtr<LayerClient> client);
- LayerClient* GetLayerClientForTesting() const { return inputs_.client.get(); }
+ // The index of this layer's node in the various property trees. These are
+ // only valid after a main frame, when Update() is called on the layer, and
+ // remain valid and in in the same state until the next main frame, or until
+ // the layer is removed from its LayerTreeHost. Otherwise kInvalidNodeId is
+ // returned.
+ int transform_tree_index() const;
+ int clip_tree_index() const;
+ int effect_tree_index() const;
+ int scroll_tree_index() const;
- virtual bool IsSnapped();
+ // While all layers have an index into the transform tree, this value
+ // indicates whether the transform tree node was created for this layer.
+ void SetHasTransformNode(bool val) { has_transform_node_ = val; }
+ bool has_transform_node() { return has_transform_node_; }
- virtual void PushPropertiesTo(LayerImpl* layer);
+ // 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
+ // optimizations like turning off the display when video is not playing,
+ // without interfering with video playback.
+ void SetMayContainVideo(bool yes);
+
+ // Stable identifier for clients. See comment in cc/trees/element_id.h.
+ void SetElementId(ElementId id);
+ ElementId element_id() const { return inputs_.element_id; }
- LayerTreeHost* GetLayerTreeHostForTesting() const { return layer_tree_host_; }
+ // Sets or gets a hint that the transform on this layer (including its
+ // position) may be changed often in the future. The layer may change its
+ // strategy for generating content as a result. PictureLayers will not attempt
+ // to raster crisply as the transform changes, allowing the client to trade
+ // off crisp content at each scale for a smoother visual and cheaper
+ // animation.
+ void SetHasWillChangeTransformHint(bool has_will_change);
+ bool has_will_change_transform_hint() const {
+ return inputs_.has_will_change_transform_hint;
+ }
- virtual ScrollbarLayerInterface* ToScrollbarLayer();
+ // Sets or gets if trilinear filtering should be used to scaling the contents
+ // of this layer and its subtree. When set the layer and its subtree will be
+ // composited together as a single unit, mip maps will be generated of the
+ // subtree together, and trilinear filtering applied when supported, if
+ // scaling during composite of the content from this layer and its subtree
+ // into the target.
+ void SetTrilinearFiltering(bool trilinear_filtering);
+ bool trilinear_filtering() const { return inputs_.trilinear_filtering; }
+ // Called on the scroll layer to trigger showing the overlay scrollbars.
+ void ShowScrollbars() { needs_show_scrollbars_ = true; }
+
+ // For tracing. Gets a recorded rasterization of this layer's contents that
+ // can be displayed inside representations of this layer. May return null, in
+ // which case the layer won't be shown with any content in the tracing
+ // display.
virtual sk_sp<SkPicture> GetPicture() const;
- // Constructs a LayerImpl of the correct runtime type for this Layer type.
+ // For tracing. Calls out to the LayerClient to get tracing data that will
+ // be attached to this layer's tracing outputs under the 'debug_info' key.
+ void UpdateDebugInfo();
+
+ // For telemetry testing. Runs a given test behaviour implemented in
+ // |benchmark| for this layer. The base class does nothing as benchmarks
+ // only exist for subclass layer types. For each subclass that the
+ // MicroBenchmark supports, the class should override this method and run the
+ // |benchmark| against this layer.
+ virtual void RunMicroBenchmark(MicroBenchmark* benchmark);
+
+ // Internal method to create the compositor thread type for this Layer.
+ // Subclasses should override this method if they want to return their own
+ // subclass of LayerImpl instead.
virtual std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl);
- bool NeedsDisplayForTesting() const { return !inputs_.update_rect.IsEmpty(); }
- void ResetNeedsDisplayForTesting() { inputs_.update_rect = gfx::Rect(); }
+ // Internal method to copy all state from this Layer to the compositor thread.
+ // Should be overridden by any subclass that has additional state, to copy
+ // that state as well. The |layer| passed in will be of the type created by
+ // CreateLayerImpl(), so can be safely down-casted if the subclass uses a
+ // different type for the compositor thread.
+ virtual void PushPropertiesTo(LayerImpl* layer);
- // Mark the layer as needing to push its properties to the LayerImpl during
- // commit.
- void SetNeedsPushProperties();
- void ResetNeedsPushPropertiesForTesting();
+ // Internal method to be overridden by Layer subclasses that need to do work
+ // during a main frame. The method should compute any state that will need to
+ // propogated to the compositor thread for the next commit, and return true
+ // if there is anything new to commit. If all layers return false, the commit
+ // may be aborted.
+ virtual bool Update();
+ // Internal method to be overriden by Layer subclasses that override Update()
+ // and require rasterization. After Update() is called, this is immediately
+ // called, and should return whether the layer will require rasterization of
+ // paths that will be difficult/slow to raster. Only layers that do
+ // rasterization via TileManager need to override this, other layers that have
+ // content generated in other ways may leave it as the default.
+ virtual bool HasSlowPaths() const;
+ // Internal method to be overriden by Layer subclasses that override Update()
+ // and require rasterization. After Update() is called, this is immediately
+ // called, and should return whether the layer will require rasterization of a
+ // drawing operation that must not be anti-aliased. In this case using MSAA to
+ // antialias the entire layer's content would produce an incorrect result.
+ // This result is considered sticky, once a layer returns true, so false
+ // positives should be avoided. Only layers that do rasterization via
+ // TileManager need to override this, other layers that have content generated
+ // in other ways may leave it as the default.
+ virtual bool HasNonAAPaint() const;
- virtual void RunMicroBenchmark(MicroBenchmark* benchmark);
+ // Internal to property tree construction. This allows a layer to request that
+ // its transform should be snapped such that the layer aligns with the pixel
+ // grid in its rendering target. This ensures that the layer is not fuzzy
+ // (unless it is being scaled). Layers may override this to return true, by
+ // default layers are not snapped.
+ virtual bool IsSnappedToPixelGridInTarget();
+
+ // Internal method that is called when a Layer is attached to a LayerTreeHost.
+ // This would happen when
+ // a) the Layer is added to an existing Layer tree that is attached to a
+ // LayerTreeHost.
+ // b) the Layer is made the root layer of a LayerTreeHost.
+ // c) the Layer is part of a Layer tree, and an ancestor is attached to a
+ // LayerTreeHost via a) or b).
+ // The |host| is the new LayerTreeHost which the Layer is now attached to.
+ // Subclasses may override this if they have data or resources which are
+ // specific to a LayerTreeHost that should be updated or reset. After this
+ // returns the Layer will hold a pointer to the new LayerTreeHost.
+ virtual void SetLayerTreeHost(LayerTreeHost* host);
- void Set3dSortingContextId(int id);
- int sorting_context_id() const { return inputs_.sorting_context_id; }
+ // Internal method to mark this layer as needing to push its state to the
+ // compositor thread during the next commit. The PushPropertiesTo() method
+ // will be called for this layer during the next commit only if this method
+ // was called before it.
+ void SetNeedsPushProperties();
+
+ // Internal method to call the LayerClient, if there is one, to inform it when
+ // overlay scrollbars have been completely hidden (due to lack of scrolling by
+ // the user).
+ void SetScrollbarsHiddenFromImplSide(bool hidden);
+ // Internal to property tree construction. A generation number for the
+ // property trees, to verify the layer's indices are pointers into the trees
+ // currently held by the LayerTreeHost. The number is updated when property
+ // trees are built from the Layer tree.
void set_property_tree_sequence_number(int sequence_number) {
property_tree_sequence_number_ = sequence_number;
}
@@ -389,91 +689,74 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
return property_tree_sequence_number_;
}
+ // Internal to property tree construction. Sets the index for this Layer's
+ // node in each property tree.
void SetTransformTreeIndex(int index);
- int transform_tree_index() const;
-
void SetClipTreeIndex(int index);
- int clip_tree_index() const;
-
void SetEffectTreeIndex(int index);
- int effect_tree_index() const;
-
void SetScrollTreeIndex(int index);
- int scroll_tree_index() const;
- void set_offset_to_transform_parent(gfx::Vector2dF offset) {
- if (offset_to_transform_parent_ == offset)
- return;
- offset_to_transform_parent_ = offset;
- SetNeedsPushProperties();
- }
+ // Internal to property tree construction. Set or get the position of this
+ // layer relative to the origin after transforming according to this layer's
+ // index into the transform tree. This translation is appended to the
+ // transform that comes from the transform tree for this layer.
+ void SetOffsetToTransformParent(gfx::Vector2dF offset);
gfx::Vector2dF offset_to_transform_parent() const {
return offset_to_transform_parent_;
}
- // TODO(enne): This needs a different name. It is a calculated value
- // from the property tree builder and not a synonym for "should
- // flatten transform".
- void set_should_flatten_transform_from_property_tree(bool should_flatten) {
- if (should_flatten_transform_from_property_tree_ == should_flatten)
- return;
- should_flatten_transform_from_property_tree_ = should_flatten;
- SetNeedsPushProperties();
- }
- bool should_flatten_transform_from_property_tree() const {
- return should_flatten_transform_from_property_tree_;
- }
-
- const gfx::Rect& visible_layer_rect_for_testing() const {
- return visible_layer_rect_;
- }
- void set_visible_layer_rect(const gfx::Rect& rect) {
- visible_layer_rect_ = rect;
- }
-
- // This is for tracking damage.
+ // Internal to property tree construction. Indicates that a property changed
+ // on this layer that may affect the position or content of all layers in this
+ // layer's subtree, including itself. This causes the layer's subtree to be
+ // considered damaged and re-displayed to the user.
void SetSubtreePropertyChanged();
bool subtree_property_changed() const { return subtree_property_changed_; }
- void SetMayContainVideo(bool yes);
-
- bool has_copy_requests_in_target_subtree();
-
- // Stable identifier for clients. See comment in cc/trees/element_id.h.
- void SetElementId(ElementId id);
- ElementId element_id() const { return inputs_.element_id; }
-
- bool HasTickingAnimationForTesting() const;
-
- void SetHasWillChangeTransformHint(bool has_will_change);
- bool has_will_change_transform_hint() const {
- return inputs_.has_will_change_transform_hint;
- }
-
- void SetTrilinearFiltering(bool trilinear_filtering);
- bool trilinear_filtering() const { return inputs_.trilinear_filtering; }
-
- MutatorHost* GetMutatorHost() const;
-
+ // Internal to property tree construction. Returns ElementListType::ACTIVE
+ // as main thread layers do not have a pending/active tree split, and
+ // animations should run normally on the main thread layer tree.
ElementListType GetElementTypeForAnimation() const;
- void SetScrollbarsHiddenFromImplSide(bool hidden);
-
- const gfx::Rect& update_rect() const { return inputs_.update_rect; }
+ // Internal to property tree construction. Whether this layer may animate its
+ // opacity on the compositor thread. Layer subclasses may override this to
+ // report true. If true, assumptions about opacity can not be made on the main
+ // thread.
+ virtual bool OpacityCanAnimateOnImplThread() const;
- LayerTreeHost* layer_tree_host() const { return layer_tree_host_; }
+ // Internal to property tree construction. Set to true if this layer or any
+ // layer below it in the tree has a CopyOutputRequest pending commit.
+ void SetSubtreeHasCopyRequest(bool subtree_has_copy_request);
+ // Internal to property tree construction. Returns true if this layer or any
+ // layer below it in the tree has a CopyOutputRequest pending commit.
+ bool SubtreeHasCopyRequest() const;
+ // Internal to property tree construction. Removes all CopyOutputRequests from
+ // this layer, moving them into |requests|.
+ void TakeCopyRequests(
+ std::vector<std::unique_ptr<viz::CopyOutputRequest>>* requests);
- // Called on the scroll layer to trigger showing the overlay scrollbars.
- void ShowScrollbars() { needs_show_scrollbars_ = true; }
+ // Internal to property tree construction. Set if the layer should not be
+ // shown when its back face is visible to the user. This is a derived value
+ // from SetDoubleSided() and SetUseParentBackfaceVisibility().
+ void SetShouldCheckBackfaceVisibility(bool should_check_backface_visibility);
+ bool should_check_backface_visibility() const {
+ return should_check_backface_visibility_;
+ }
- bool has_transform_node() { return has_transform_node_; }
- void SetHasTransformNode(bool val) { has_transform_node_ = val; }
+ // Internal to property tree construction. The value here derives from
+ // should_flatten_transform() along with other state, and is for internal use
+ // in order to flatten the layer's ScreenSpaceTransform() in cases where the
+ // property tree did not handle it.
+ void SetShouldFlattenScreenSpaceTransformFromPropertyTree(bool should);
+ bool should_flatten_screen_space_transform_from_property_tree() const {
+ return should_flatten_screen_space_transform_from_property_tree_;
+ }
protected:
friend class LayerImpl;
friend class TreeSynchronizer;
- virtual ~Layer();
+
Layer();
+ virtual ~Layer();
// These SetNeeds functions are in order of severity of update:
//
@@ -495,11 +778,18 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// Will recalculate whether the layer draws content and set draws_content_
// appropriately.
void UpdateDrawsContent(bool has_drawable_content);
+ // May be overridden by subclasses if they have optional content, to return
+ // false if there is no content to be displayed. If they do have content, then
+ // they should return the value from this base class method.
virtual bool HasDrawableContent() const;
// Called when the layer's number of drawable descendants changes.
void AddDrawableDescendants(int num);
+ // For debugging. Returns false if the LayerTreeHost this layer is attached to
+ // is in the process of updating layers for a BeginMainFrame. Layer properties
+ // should be changed by the client before the BeginMainFrame, and should not
+ // be changed while the frame is being generated for commit.
bool IsPropertyChangeAllowed() const;
// When true, the layer is about to perform an update. Any commit requests
@@ -516,8 +806,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void OnOpacityAnimated(float opacity);
void OnTransformAnimated(const gfx::Transform& transform);
- bool ScrollOffsetAnimationWasInterrupted() const;
-
void AddClipChild(Layer* child);
void RemoveClipChild(Layer* child);
@@ -557,17 +845,12 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
LayerList children;
- // The update rect is the region of the compositor resource that was
- // actually updated by the compositor. For layers that may do updating
- // outside the compositor's control (i.e. plugin layers), this information
- // is not available and the update rect will remain empty.
- // Note this rect is in layer space (not content space).
gfx::Rect update_rect;
gfx::Size bounds;
bool masks_to_bounds;
- scoped_refptr<Layer> mask_layer;
+ scoped_refptr<PictureLayer> mask_layer;
float opacity;
SkBlendMode blend_mode;
@@ -649,7 +932,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
base::WeakPtr<LayerClient> client;
std::unique_ptr<base::trace_event::TracedValue> debug_info;
- base::Callback<void(const gfx::ScrollOffset&, const ElementId&)>
+ base::RepeatingCallback<void(const gfx::ScrollOffset&, const ElementId&)>
did_scroll_callback;
std::vector<std::unique_ptr<viz::CopyOutputRequest>> copy_requests;
@@ -674,7 +957,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
int scroll_tree_index_;
int property_tree_sequence_number_;
gfx::Vector2dF offset_to_transform_parent_;
- bool should_flatten_transform_from_property_tree_ : 1;
+ bool should_flatten_screen_space_transform_from_property_tree_ : 1;
bool draws_content_ : 1;
bool should_check_backface_visibility_ : 1;
// Force use of and cache render surface.
@@ -683,9 +966,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
bool subtree_property_changed_ : 1;
bool may_contain_video_ : 1;
bool needs_show_scrollbars_ : 1;
- // Whether the nodes referred to by *_tree_index_ "belong" to this
- // layer. Only applicable if LayerTreeSettings.use_layer_lists is
- // false.
bool has_transform_node_ : 1;
// This value is valid only when LayerTreeHost::has_copy_request() is true
bool subtree_has_copy_request_ : 1;
@@ -693,10 +973,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
std::unique_ptr<std::set<Layer*>> clip_children_;
- // These all act like draw properties, so don't need push properties.
- gfx::Rect visible_layer_rect_;
- size_t num_unclipped_descendants_;
-
DISALLOW_COPY_AND_ASSIGN(Layer);
};
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index 2eee6d48f5a..e5dad6df494 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -23,7 +23,6 @@
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/input/scroll_state.h"
#include "cc/layers/layer.h"
-#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/trees/clip_node.h"
#include "cc/trees/draw_property_utils.h"
#include "cc/trees/effect_node.h"
@@ -34,6 +33,7 @@
#include "cc/trees/proxy.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/transform_node.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/quads/debug_border_draw_quad.h"
#include "components/viz/common/quads/render_pass.h"
@@ -52,7 +52,7 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
main_thread_scrolling_reasons_(
MainThreadScrollingReason::kNotScrollingOnMain),
scrollable_(false),
- should_flatten_transform_from_property_tree_(false),
+ should_flatten_screen_space_transform_from_property_tree_(false),
layer_property_changed_not_from_property_trees_(false),
layer_property_changed_from_property_trees_(false),
may_contain_video_(false),
@@ -74,7 +74,6 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
current_draw_mode_(DRAW_MODE_NONE),
debug_info_(nullptr),
has_will_change_transform_hint_(false),
- trilinear_filtering_(false),
needs_push_properties_(false),
scrollbars_hidden_(false),
needs_show_scrollbars_(false),
@@ -84,15 +83,14 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
DCHECK(layer_tree_impl_);
layer_tree_impl_->RegisterLayer(this);
- layer_tree_impl_->AddToElementMap(this);
+ layer_tree_impl_->AddToElementLayerList(element_id_);
SetNeedsPushProperties();
}
LayerImpl::~LayerImpl() {
- DCHECK_EQ(DRAW_MODE_NONE, current_draw_mode_);
layer_tree_impl_->UnregisterLayer(this);
- layer_tree_impl_->RemoveFromElementMap(this);
+ layer_tree_impl_->RemoveFromElementLayerList(element_id_);
TRACE_EVENT_OBJECT_DELETED_WITH_ID(
TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerImpl", this);
}
@@ -101,14 +99,6 @@ void LayerImpl::SetHasWillChangeTransformHint(bool has_will_change) {
has_will_change_transform_hint_ = has_will_change;
}
-void LayerImpl::SetTrilinearFiltering(bool trilinear_filtering) {
- trilinear_filtering_ = trilinear_filtering;
-}
-
-MutatorHost* LayerImpl::GetMutatorHost() const {
- return layer_tree_impl_ ? layer_tree_impl_->mutator_host() : nullptr;
-}
-
ElementListType LayerImpl::GetElementTypeForAnimation() const {
return IsActive() ? ElementListType::ACTIVE : ElementListType::PENDING;
}
@@ -175,16 +165,18 @@ void LayerImpl::PopulateScaledSharedQuadState(viz::SharedQuadState* state,
}
bool LayerImpl::WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) {
- // WillDraw/DidDraw must be matched.
- DCHECK_NE(DRAW_MODE_NONE, draw_mode);
- DCHECK_EQ(DRAW_MODE_NONE, current_draw_mode_);
+ viz::ClientResourceProvider* resource_provider) {
+ if (visible_layer_rect().IsEmpty() ||
+ draw_properties().occlusion_in_content_space.IsOccluded(
+ visible_layer_rect())) {
+ return false;
+ }
+
current_draw_mode_ = draw_mode;
return true;
}
-void LayerImpl::DidDraw(LayerTreeResourceProvider* resource_provider) {
- DCHECK_NE(DRAW_MODE_NONE, current_draw_mode_);
+void LayerImpl::DidDraw(viz::ClientResourceProvider* resource_provider) {
current_draw_mode_ = DRAW_MODE_NONE;
}
@@ -294,8 +286,8 @@ std::unique_ptr<LayerImpl> LayerImpl::CreateLayerImpl(
return LayerImpl::Create(tree_impl, layer_id_);
}
-bool LayerImpl::IsSnapped() {
- return scrollable();
+bool LayerImpl::IsSnappedToPixelGridInTarget() {
+ return false;
}
void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
@@ -309,8 +301,8 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->has_transform_node_ = has_transform_node_;
layer->offset_to_transform_parent_ = offset_to_transform_parent_;
layer->main_thread_scrolling_reasons_ = main_thread_scrolling_reasons_;
- layer->should_flatten_transform_from_property_tree_ =
- should_flatten_transform_from_property_tree_;
+ layer->should_flatten_screen_space_transform_from_property_tree_ =
+ should_flatten_screen_space_transform_from_property_tree_;
layer->masks_to_bounds_ = masks_to_bounds_;
layer->contents_opaque_ = contents_opaque_;
layer->may_contain_video_ = may_contain_video_;
@@ -321,6 +313,7 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
hit_testable_without_draws_content_;
layer->non_fast_scrollable_region_ = non_fast_scrollable_region_;
layer->touch_action_region_ = touch_action_region_;
+ layer->wheel_event_handler_region_ = wheel_event_handler_region_;
layer->background_color_ = background_color_;
layer->safe_opaque_background_color_ = safe_opaque_background_color_;
layer->position_ = position_;
@@ -329,7 +322,6 @@ 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->trilinear_filtering_ = trilinear_filtering_;
layer->scrollbars_hidden_ = scrollbars_hidden_;
if (needs_show_scrollbars_)
layer->needs_show_scrollbars_ = needs_show_scrollbars_;
@@ -421,6 +413,11 @@ std::unique_ptr<base::DictionaryValue> LayerImpl::LayerAsJson() {
result->Set("TouchRegion", std::move(region));
}
+ if (!wheel_event_handler_region_.IsEmpty()) {
+ std::unique_ptr<base::Value> region = wheel_event_handler_region_.AsValue();
+ result->Set("WheelRegion", std::move(region));
+ }
+
return result;
}
@@ -476,7 +473,7 @@ void LayerImpl::NoteLayerPropertyChangedFromPropertyTrees() {
void LayerImpl::ValidateQuadResourcesInternal(viz::DrawQuad* quad) const {
#if DCHECK_IS_ON()
- const LayerTreeResourceProvider* resource_provider =
+ const viz::ClientResourceProvider* resource_provider =
layer_tree_impl_->resource_provider();
for (viz::ResourceId resource_id : quad->resources)
resource_provider->ValidateResource(resource_id);
@@ -643,9 +640,9 @@ void LayerImpl::SetElementId(ElementId element_id) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "LayerImpl::SetElementId",
"element", element_id.AsValue().release());
- layer_tree_impl_->RemoveFromElementMap(this);
+ layer_tree_impl_->RemoveFromElementLayerList(element_id_);
element_id_ = element_id;
- layer_tree_impl_->AddToElementMap(this);
+ layer_tree_impl_->AddToElementLayerList(element_id_);
SetNeedsPushProperties();
}
@@ -683,6 +680,10 @@ void LayerImpl::DidBeginTracing() {}
void LayerImpl::ReleaseResources() {}
+void LayerImpl::OnPurgeMemory() {
+ ReleaseResources();
+}
+
void LayerImpl::ReleaseTileResources() {}
void LayerImpl::RecreateTileResources() {}
@@ -753,6 +754,11 @@ void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const {
touch_action_region_.region().AsValueInto(state);
state->EndArray();
}
+ if (!wheel_event_handler_region_.IsEmpty()) {
+ state->BeginArray("wheel_event_handler_region");
+ wheel_event_handler_region_.AsValueInto(state);
+ state->EndArray();
+ }
if (!non_fast_scrollable_region_.IsEmpty()) {
state->BeginArray("non_fast_scrollable_region");
non_fast_scrollable_region_.AsValueInto(state);
@@ -765,8 +771,6 @@ void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const {
state->SetBoolean("has_will_change_transform_hint",
has_will_change_transform_hint());
- state->SetBoolean("trilinear_filtering", trilinear_filtering());
-
MainThreadScrollingReason::AddToTracedValue(main_thread_scrolling_reasons_,
*state);
diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h
index d130a695d45..8a2f9a68c15 100644
--- a/chromium/cc/layers/layer_impl.h
+++ b/chromium/cc/layers/layer_impl.h
@@ -33,7 +33,6 @@
#include "cc/layers/touch_action_region.h"
#include "cc/tiles/tile_priority.h"
#include "cc/trees/element_id.h"
-#include "cc/trees/mutator_host_client.h"
#include "cc/trees/target_property.h"
#include "components/viz/common/quads/shared_quad_state.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -51,6 +50,7 @@ class DictionaryValue;
}
namespace viz {
+class ClientResourceProvider;
class RenderPass;
}
@@ -58,9 +58,7 @@ namespace cc {
class AppendQuadsData;
class LayerTreeImpl;
-class LayerTreeResourceProvider;
class MicroBenchmarkImpl;
-class MutatorHost;
class PrioritizedTile;
class ScrollbarLayerImplBase;
class SimpleEnclosedRegion;
@@ -107,18 +105,19 @@ class CC_EXPORT LayerImpl {
void SetScrollTreeIndex(int index);
int scroll_tree_index() const { return scroll_tree_index_; }
- void set_offset_to_transform_parent(const gfx::Vector2dF& offset) {
+ void SetOffsetToTransformParent(const gfx::Vector2dF& offset) {
offset_to_transform_parent_ = offset;
}
gfx::Vector2dF offset_to_transform_parent() const {
return offset_to_transform_parent_;
}
- void set_should_flatten_transform_from_property_tree(bool should_flatten) {
- should_flatten_transform_from_property_tree_ = should_flatten;
+ void SetShouldFlattenScreenSpaceTransformFromPropertyTree(
+ bool should_flatten) {
+ should_flatten_screen_space_transform_from_property_tree_ = should_flatten;
}
- bool should_flatten_transform_from_property_tree() const {
- return should_flatten_transform_from_property_tree_;
+ bool should_flatten_screen_space_transform_from_property_tree() const {
+ return should_flatten_screen_space_transform_from_property_tree_;
}
bool is_clipped() const { return draw_properties_.is_clipped; }
@@ -134,14 +133,12 @@ class CC_EXPORT LayerImpl {
// 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
- // the layer is destroyed. To enforce this, any class that overrides
- // WillDraw/DidDraw must call the base class version only if WillDraw
- // returns true.
+ // the layer is destroyed.
virtual bool WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider);
+ viz::ClientResourceProvider* resource_provider);
virtual void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) {}
- virtual void DidDraw(LayerTreeResourceProvider* resource_provider);
+ virtual void DidDraw(viz::ClientResourceProvider* resource_provider);
// Verify that the resource ids in the quad are valid.
void ValidateQuadResources(viz::DrawQuad* quad) const {
@@ -332,6 +329,16 @@ class CC_EXPORT LayerImpl {
return touch_action_region_;
}
+ // Set or get the region that contains wheel event handler.
+ // The |wheel_event_handler_region| specify the area where wheel event handler
+ // could block impl scrolling.
+ void SetWheelEventHandlerRegion(const Region& wheel_event_handler_region) {
+ wheel_event_handler_region_ = wheel_event_handler_region;
+ }
+ const Region& wheel_event_handler_region() const {
+ return wheel_event_handler_region_;
+ }
+
// Note this rect is in layer space (not content space).
void SetUpdateRect(const gfx::Rect& update_rect);
const gfx::Rect& update_rect() const { return update_rect_; }
@@ -365,8 +372,13 @@ class CC_EXPORT LayerImpl {
// that rendered this layer was lost.
virtual void ReleaseResources();
+ // Releases resources in response to memory pressure. The default
+ // implementation just calls ReleaseResources() and subclasses will override
+ // if that's not appropriate.
+ virtual void OnPurgeMemory();
+
// Release tile resources held by this layer. Called when a rendering mode
- // switch has occured and tiles are no longer valid.
+ // switch has occurred and tiles are no longer valid.
virtual void ReleaseTileResources();
// Recreate tile resources held by this layer after they were released by a
@@ -374,9 +386,13 @@ class CC_EXPORT LayerImpl {
virtual void RecreateTileResources();
virtual std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl);
- virtual bool IsSnapped();
virtual void PushPropertiesTo(LayerImpl* layer);
+ // Internal to property tree construction (which only happens in tests on a
+ // LayerImpl tree. See Layer::IsSnappedToPixelGridInTarget() for explanation,
+ // as this mirrors that method.
+ virtual bool IsSnappedToPixelGridInTarget();
+
virtual void GetAllPrioritizedTilesForTracing(
std::vector<PrioritizedTile>* prioritized_tiles) const;
virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
@@ -427,11 +443,6 @@ class CC_EXPORT LayerImpl {
return has_will_change_transform_hint_;
}
- void SetTrilinearFiltering(bool trilinear_filtering);
- bool trilinear_filtering() const { return trilinear_filtering_; }
-
- MutatorHost* GetMutatorHost() const;
-
ElementListType GetElementTypeForAnimation() const;
void set_needs_show_scrollbars(bool yes) { needs_show_scrollbars_ = yes; }
@@ -493,7 +504,7 @@ class CC_EXPORT LayerImpl {
// |scroll_container_bounds|).
bool scrollable_ : 1;
- bool should_flatten_transform_from_property_tree_ : 1;
+ bool should_flatten_screen_space_transform_from_property_tree_ : 1;
// Tracks if drawing-related properties have changed since last redraw.
// TODO(wutao): We want to distinquish the sources of change so that we can
@@ -525,6 +536,7 @@ class CC_EXPORT LayerImpl {
Region non_fast_scrollable_region_;
TouchActionRegion touch_action_region_;
+ Region wheel_event_handler_region_;
SkColor background_color_;
SkColor safe_opaque_background_color_;
@@ -566,7 +578,6 @@ class CC_EXPORT LayerImpl {
base::trace_event::TracedValue* debug_info_;
bool has_will_change_transform_hint_ : 1;
- bool trilinear_filtering_ : 1;
bool needs_push_properties_ : 1;
bool scrollbars_hidden_ : 1;
diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc
index 52977e8b2b2..551eced4977 100644
--- a/chromium/cc/layers/layer_impl_unittest.cc
+++ b/chromium/cc/layers/layer_impl_unittest.cc
@@ -122,7 +122,7 @@ TEST(LayerImplTest, VerifyPendingLayerChangesAreTrackedProperly) {
FakeLayerTreeFrameSink::Create3d();
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- EXPECT_TRUE(host_impl.InitializeRenderer(layer_tree_frame_sink.get()));
+ EXPECT_TRUE(host_impl.InitializeFrameSink(layer_tree_frame_sink.get()));
host_impl.CreatePendingTree();
std::unique_ptr<LayerImpl> root_ptr =
LayerImpl::Create(host_impl.pending_tree(), 2);
@@ -208,7 +208,7 @@ TEST(LayerImplTest, VerifyActiveLayerChangesAreTrackedProperly) {
FakeLayerTreeFrameSink::Create3d();
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- EXPECT_TRUE(host_impl.InitializeRenderer(layer_tree_frame_sink.get()));
+ EXPECT_TRUE(host_impl.InitializeFrameSink(layer_tree_frame_sink.get()));
std::unique_ptr<LayerImpl> root_ptr =
LayerImpl::Create(host_impl.active_tree(), 2);
LayerImpl* root = root_ptr.get();
@@ -285,7 +285,7 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
FakeLayerTreeFrameSink::Create3d();
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- EXPECT_TRUE(host_impl.InitializeRenderer(layer_tree_frame_sink.get()));
+ EXPECT_TRUE(host_impl.InitializeFrameSink(layer_tree_frame_sink.get()));
host_impl.active_tree()->SetRootLayerForTesting(
LayerImpl::Create(host_impl.active_tree(), 1));
LayerImpl* root = host_impl.active_tree()->root_layer_for_testing();
@@ -397,7 +397,7 @@ TEST(LayerImplTest, SafeOpaqueBackgroundColor) {
FakeLayerTreeFrameSink::Create3d();
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- EXPECT_TRUE(host_impl.InitializeRenderer(layer_tree_frame_sink.get()));
+ EXPECT_TRUE(host_impl.InitializeFrameSink(layer_tree_frame_sink.get()));
host_impl.active_tree()->SetRootLayerForTesting(
LayerImpl::Create(host_impl.active_tree(), 1));
LayerImpl* layer = host_impl.active_tree()->root_layer_for_testing();
diff --git a/chromium/cc/layers/layer_list_iterator.cc b/chromium/cc/layers/layer_list_iterator.cc
index 1637b842331..7ff7c68ca6e 100644
--- a/chromium/cc/layers/layer_list_iterator.cc
+++ b/chromium/cc/layers/layer_list_iterator.cc
@@ -36,7 +36,7 @@ static LayerImpl* ChildAt(LayerImpl* layer, int index) {
}
static Layer* ChildAt(Layer* layer, int index) {
- return layer->child_at(index);
+ return layer->children()[index].get();
}
template <typename LayerType>
diff --git a/chromium/cc/layers/layer_list_iterator_unittest.cc b/chromium/cc/layers/layer_list_iterator_unittest.cc
index 0c984bfc8d1..f3f62fc11f4 100644
--- a/chromium/cc/layers/layer_list_iterator_unittest.cc
+++ b/chromium/cc/layers/layer_list_iterator_unittest.cc
@@ -207,7 +207,7 @@ TEST(LayerListIteratorTest, VerifyTraversalOrderImpl) {
FakeLayerTreeFrameSink::Create3d();
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- EXPECT_TRUE(host_impl.InitializeRenderer(layer_tree_frame_sink.get()));
+ EXPECT_TRUE(host_impl.InitializeFrameSink(layer_tree_frame_sink.get()));
// This test constructs the following tree.
// 1
@@ -260,7 +260,7 @@ TEST(LayerListIteratorTest, VerifySingleLayerImpl) {
FakeLayerTreeFrameSink::Create3d();
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- EXPECT_TRUE(host_impl.InitializeRenderer(layer_tree_frame_sink.get()));
+ EXPECT_TRUE(host_impl.InitializeFrameSink(layer_tree_frame_sink.get()));
// This test constructs a tree consisting of a single layer.
std::unique_ptr<LayerImpl> layer1 =
@@ -295,7 +295,7 @@ TEST(LayerListReverseIteratorTest, VerifyTraversalOrderImpl) {
FakeLayerTreeFrameSink::Create3d();
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- EXPECT_TRUE(host_impl.InitializeRenderer(layer_tree_frame_sink.get()));
+ EXPECT_TRUE(host_impl.InitializeFrameSink(layer_tree_frame_sink.get()));
// This test constructs the following tree.
// 1
@@ -350,7 +350,7 @@ TEST(LayerListReverseIteratorTest, VerifySingleLayerImpl) {
FakeLayerTreeFrameSink::Create3d();
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- EXPECT_TRUE(host_impl.InitializeRenderer(layer_tree_frame_sink.get()));
+ EXPECT_TRUE(host_impl.InitializeFrameSink(layer_tree_frame_sink.get()));
// This test constructs a tree consisting of a single layer.
std::unique_ptr<LayerImpl> layer1 =
diff --git a/chromium/cc/layers/layer_position_constraint_unittest.cc b/chromium/cc/layers/layer_position_constraint_unittest.cc
index aa03cc5629d..aa58b7f57af 100644
--- a/chromium/cc/layers/layer_position_constraint_unittest.cc
+++ b/chromium/cc/layers/layer_position_constraint_unittest.cc
@@ -20,20 +20,6 @@
namespace cc {
namespace {
-class LayerWithForcedDrawsContent : public Layer {
- public:
- LayerWithForcedDrawsContent() = default;
-
- bool DrawsContent() const override;
-
- private:
- ~LayerWithForcedDrawsContent() override = default;
-};
-
-bool LayerWithForcedDrawsContent::DrawsContent() const {
- return true;
-}
-
void SetLayerPropertiesForTesting(Layer* layer,
const gfx::Transform& transform,
const gfx::Point3F& transform_origin,
@@ -94,9 +80,10 @@ class LayerPositionConstraintTest : public testing::Test {
outer_viewport_container_layer_ = Layer::Create();
child_transform_layer_ = Layer::Create();
child_ = Layer::Create();
- grand_child_ = base::WrapRefCounted(new LayerWithForcedDrawsContent());
- great_grand_child_ =
- base::WrapRefCounted(new LayerWithForcedDrawsContent());
+ grand_child_ = Layer::Create();
+ grand_child_->SetIsDrawable(true);
+ great_grand_child_ = Layer::Create();
+ great_grand_child_->SetIsDrawable(true);
gfx::Transform IdentityMatrix;
gfx::Point3F transform_origin;
@@ -569,8 +556,8 @@ TEST_F(LayerPositionConstraintTest,
// transform.
// Add one more layer to the test tree for this scenario.
- scoped_refptr<Layer> fixed_position_child =
- base::WrapRefCounted(new LayerWithForcedDrawsContent());
+ scoped_refptr<Layer> fixed_position_child = Layer::Create();
+ fixed_position_child->SetIsDrawable(true);
SetLayerPropertiesForTesting(fixed_position_child.get(), gfx::Transform(),
gfx::Point3F(), gfx::PointF(),
gfx::Size(100, 100), true);
@@ -729,8 +716,8 @@ TEST_F(
// surfaces is accumulated properly in the final matrix transform.
// Add one more layer to the test tree for this scenario.
- scoped_refptr<Layer> fixed_position_child =
- base::WrapRefCounted(new LayerWithForcedDrawsContent());
+ scoped_refptr<Layer> fixed_position_child = Layer::Create();
+ fixed_position_child->SetIsDrawable(true);
SetLayerPropertiesForTesting(fixed_position_child.get(), gfx::Transform(),
gfx::Point3F(), gfx::PointF(),
gfx::Size(100, 100), true);
@@ -1066,8 +1053,8 @@ TEST_F(LayerPositionConstraintTest,
// would still have to compensate with respect to its container.
// Add one more layer to the hierarchy for this test.
- scoped_refptr<Layer> great_great_grand_child =
- base::WrapRefCounted(new LayerWithForcedDrawsContent());
+ scoped_refptr<Layer> great_great_grand_child = Layer::Create();
+ great_great_grand_child->SetIsDrawable(true);
great_grand_child_->AddChild(great_great_grand_child);
child_->SetIsContainerForFixedPositionLayers(true);
@@ -1122,8 +1109,8 @@ TEST_F(LayerPositionConstraintTest,
ScrollCompensationForOuterViewportBoundsDelta) {
// This test checks for correct scroll compensation when the fixed-position
// container is the outer viewport scroll layer and has non-zero bounds delta.
- scoped_refptr<Layer> fixed_child =
- base::WrapRefCounted(new LayerWithForcedDrawsContent());
+ scoped_refptr<Layer> fixed_child = Layer::Create();
+ fixed_child->SetIsDrawable(true);
fixed_child->SetBounds(gfx::Size(300, 300));
child_->AddChild(fixed_child);
fixed_child->SetPositionConstraint(fixed_to_top_left_);
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index 594552cc344..d8c5f9616d4 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -13,8 +13,10 @@
#include "cc/base/math_util.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/layers/layer_impl.h"
+#include "cc/layers/picture_layer.h"
#include "cc/layers/solid_color_scrollbar_layer.h"
#include "cc/test/animation_test_common.h"
+#include "cc/test/fake_content_layer_client.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"
@@ -115,6 +117,10 @@ class MockLayerTreeHost : public LayerTreeHost {
MOCK_METHOD0(SetNeedsFullTreeSync, void());
};
+bool LayerNeedsDisplay(Layer* layer) {
+ return !layer->update_rect().IsEmpty();
+}
+
class LayerTest : public testing::Test {
public:
LayerTest()
@@ -161,6 +167,11 @@ class LayerTest : public testing::Test {
animation_host_ = nullptr;
}
+ void SimulateCommitForLayer(Layer* layer) {
+ layer->PushPropertiesTo(
+ layer->CreateLayerImpl(host_impl_.active_tree()).get());
+ }
+
void VerifyTestTreeInitialState() const {
ASSERT_EQ(3U, parent_->children().size());
EXPECT_EQ(child1_, parent_->children()[0]);
@@ -246,7 +257,8 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
scoped_refptr<Layer> child = Layer::Create();
scoped_refptr<Layer> child2 = Layer::Create();
scoped_refptr<Layer> grand_child = Layer::Create();
- scoped_refptr<Layer> dummy_layer1 = Layer::Create();
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> mask_layer1 = PictureLayer::Create(&client);
layer_tree_host_->SetRootLayer(root);
root->AddChild(child);
@@ -256,6 +268,18 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
child->SetForceRenderSurfaceForTesting(true);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
child2->SetScrollParent(grand_child.get());
+
+ // Resizing without a mask layer or masks_to_bounds, should only require a
+ // regular commit. Note that a layer and its mask should match sizes, but
+ // the mask isn't in the tree yet, so won't need its own commit.
+ gfx::Size arbitrary_size = gfx::Size(1, 2);
+ EXPECT_SET_NEEDS_COMMIT(1, root->SetBounds(arbitrary_size));
+ EXPECT_SET_NEEDS_COMMIT(0, mask_layer1->SetBounds(arbitrary_size));
+ EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1);
+ EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetMaskLayer(mask_layer1.get()));
+
+ // Set up the impl layers after the full tree is constructed, including the
+ // mask layer.
SkBlendMode arbitrary_blend_mode = SkBlendMode::kMultiply;
std::unique_ptr<LayerImpl> root_impl =
LayerImpl::Create(host_impl_.active_tree(), root->id());
@@ -265,30 +289,21 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
LayerImpl::Create(host_impl_.active_tree(), child2->id());
std::unique_ptr<LayerImpl> grand_child_impl =
LayerImpl::Create(host_impl_.active_tree(), grand_child->id());
- std::unique_ptr<LayerImpl> dummy_layer1_impl =
- LayerImpl::Create(host_impl_.active_tree(), dummy_layer1->id());
+ std::unique_ptr<LayerImpl> mask_layer1_impl =
+ mask_layer1->CreateLayerImpl(host_impl_.active_tree());
- // Resizing without a mask layer or masks_to_bounds, should only require a
- // regular commit. Note that a layer and its mask should match sizes, but
- // the mask isn't in the tree yet, so won't need its own commit.
- gfx::Size arbitrary_size = gfx::Size(1, 2);
- EXPECT_SET_NEEDS_COMMIT(1, root->SetBounds(arbitrary_size));
- EXPECT_SET_NEEDS_COMMIT(0, dummy_layer1->SetBounds(arbitrary_size));
-
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1);
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetMaskLayer(dummy_layer1.get()));
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());
- dummy_layer1->PushPropertiesTo(dummy_layer1_impl.get()));
+ mask_layer1->PushPropertiesTo(mask_layer1_impl.get()););
// Once there is a mask layer, resizes require subtree properties to update.
arbitrary_size = gfx::Size(11, 22);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBounds(arbitrary_size));
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(dummy_layer1->SetBounds(arbitrary_size));
+ EXECUTE_AND_VERIFY_SUBTREE_CHANGED(mask_layer1->SetBounds(arbitrary_size));
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetMasksToBounds(true));
@@ -323,6 +338,22 @@ 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->SetTrilinearFiltering(true));
+ 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->SetTrilinearFiltering(false));
+ 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());
@@ -351,7 +382,7 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
arbitrary_size = gfx::Size(111, 222);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBounds(arbitrary_size));
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(dummy_layer1->SetBounds(arbitrary_size));
+ EXECUTE_AND_VERIFY_SUBTREE_CHANGED(mask_layer1->SetBounds(arbitrary_size));
EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
root->PushPropertiesTo(root_impl.get());
child->PushPropertiesTo(child_impl.get());
@@ -573,11 +604,11 @@ TEST_F(LayerTest, ReplaceChildWithNewChild) {
EXPECT_SET_NEEDS_FULL_TREE_SYNC(
AtLeast(1), parent_->ReplaceChild(child2_.get(), child4));
- EXPECT_FALSE(parent_->NeedsDisplayForTesting());
- EXPECT_FALSE(child1_->NeedsDisplayForTesting());
- EXPECT_FALSE(child2_->NeedsDisplayForTesting());
- EXPECT_FALSE(child3_->NeedsDisplayForTesting());
- EXPECT_FALSE(child4->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(parent_.get()));
+ EXPECT_FALSE(LayerNeedsDisplay(child1_.get()));
+ EXPECT_FALSE(LayerNeedsDisplay(child2_.get()));
+ EXPECT_FALSE(LayerNeedsDisplay(child3_.get()));
+ EXPECT_FALSE(LayerNeedsDisplay(child4.get()));
ASSERT_EQ(static_cast<size_t>(3), parent_->children().size());
EXPECT_EQ(child1_, parent_->children()[0]);
@@ -634,7 +665,7 @@ TEST_F(LayerTest, DeleteRemovedScrollParent) {
EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, child2->RemoveFromParent());
- child1->ResetNeedsPushPropertiesForTesting();
+ SimulateCommitForLayer(child1.get());
EXPECT_SET_NEEDS_COMMIT(1, child1->SetScrollParent(nullptr));
EXPECT_TRUE(
@@ -688,37 +719,6 @@ TEST_F(LayerTest, RemoveAllChildren) {
EXPECT_FALSE(child3_->parent());
}
-TEST_F(LayerTest, SetChildren) {
- scoped_refptr<Layer> old_parent = Layer::Create();
- scoped_refptr<Layer> new_parent = Layer::Create();
-
- scoped_refptr<Layer> child1 = Layer::Create();
- scoped_refptr<Layer> child2 = Layer::Create();
-
- LayerList new_children;
- new_children.push_back(child1);
- new_children.push_back(child2);
-
- // Set up and verify initial test conditions: child1 has a parent, child2 has
- // no parent.
- old_parent->AddChild(child1);
- ASSERT_EQ(0U, new_parent->children().size());
- EXPECT_EQ(old_parent.get(), child1->parent());
- EXPECT_FALSE(child2->parent());
-
- EXPECT_SET_NEEDS_FULL_TREE_SYNC(1,
- layer_tree_host_->SetRootLayer(new_parent));
-
- EXPECT_SET_NEEDS_FULL_TREE_SYNC(
- AtLeast(1), new_parent->SetChildren(new_children));
-
- ASSERT_EQ(2U, new_parent->children().size());
- EXPECT_EQ(new_parent.get(), child1->parent());
- EXPECT_EQ(new_parent.get(), child2->parent());
-
- EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(nullptr));
-}
-
TEST_F(LayerTest, HasAncestor) {
scoped_refptr<Layer> parent = Layer::Create();
EXPECT_FALSE(parent->HasAncestor(parent.get()));
@@ -812,44 +812,42 @@ TEST_F(LayerTest, CheckSetNeedsDisplayCausesCorrectBehavior) {
gfx::Rect out_of_bounds_dirty_rect = gfx::Rect(400, 405, 500, 502);
// Before anything, test_layer should not be dirty.
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
// This is just initialization, but SetNeedsCommit behavior is verified anyway
// to avoid warnings.
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBounds(test_bounds));
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
// The real test begins here.
- test_layer->ResetNeedsDisplayForTesting();
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ SimulateCommitForLayer(test_layer.get());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
// Case 1: Layer should accept dirty rects that go beyond its bounds.
- test_layer->ResetNeedsDisplayForTesting();
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
EXPECT_SET_NEEDS_UPDATE(
1, test_layer->SetNeedsDisplayRect(out_of_bounds_dirty_rect));
- EXPECT_TRUE(test_layer->NeedsDisplayForTesting());
- test_layer->ResetNeedsDisplayForTesting();
+ EXPECT_TRUE(LayerNeedsDisplay(test_layer.get()));
+ SimulateCommitForLayer(test_layer.get());
// Case 2: SetNeedsDisplay() without the dirty rect arg.
- test_layer->ResetNeedsDisplayForTesting();
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
EXPECT_SET_NEEDS_UPDATE(1, test_layer->SetNeedsDisplay());
- EXPECT_TRUE(test_layer->NeedsDisplayForTesting());
- test_layer->ResetNeedsDisplayForTesting();
+ EXPECT_TRUE(LayerNeedsDisplay(test_layer.get()));
+ SimulateCommitForLayer(test_layer.get());
// Case 3: SetNeedsDisplay() with an empty rect.
- test_layer->ResetNeedsDisplayForTesting();
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
EXPECT_SET_NEEDS_COMMIT(0, test_layer->SetNeedsDisplayRect(gfx::Rect()));
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
+ SimulateCommitForLayer(test_layer.get());
// Case 4: SetNeedsDisplay() with a non-drawable layer
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(false));
- test_layer->ResetNeedsDisplayForTesting();
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ SimulateCommitForLayer(test_layer.get());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
EXPECT_SET_NEEDS_UPDATE(0, test_layer->SetNeedsDisplayRect(dirty_rect));
- EXPECT_TRUE(test_layer->NeedsDisplayForTesting());
+ EXPECT_TRUE(LayerNeedsDisplay(test_layer.get()));
}
TEST_F(LayerTest, TestSettingMainThreadScrollingReason) {
@@ -859,7 +857,7 @@ TEST_F(LayerTest, TestSettingMainThreadScrollingReason) {
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(true));
// sanity check of initial test condition
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
uint32_t reasons = 0, reasons_to_clear = 0, reasons_after_clearing = 0;
reasons |= MainThreadScrollingReason::kThreadedScrollingDisabled;
@@ -912,10 +910,11 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
layer_tree_host_->SetRootLayer(test_layer));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(true));
- scoped_refptr<Layer> dummy_layer1 = Layer::Create();
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> mask_layer1 = PictureLayer::Create(&client);
// sanity check of initial test condition
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
// Next, test properties that should call SetNeedsCommit (but not
// SetNeedsDisplay). All properties need to be set to new values in order for
@@ -950,11 +949,11 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHideLayerAndSubtree(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetElementId(ElementId(2)));
- EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, test_layer->SetMaskLayer(
- dummy_layer1.get()));
+ EXPECT_SET_NEEDS_FULL_TREE_SYNC(1,
+ test_layer->SetMaskLayer(mask_layer1.get()));
// The above tests should not have caused a change to the needs_display flag.
- EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+ EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
// As layers are removed from the tree, they will cause a tree sync.
EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times((AnyNumber()));
@@ -1035,8 +1034,9 @@ TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForOpacity) {
TEST_F(LayerTest, MaskHasParent) {
scoped_refptr<Layer> parent = Layer::Create();
scoped_refptr<Layer> child = Layer::Create();
- scoped_refptr<Layer> mask = Layer::Create();
- scoped_refptr<Layer> mask_replacement = Layer::Create();
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
+ scoped_refptr<PictureLayer> mask_replacement = PictureLayer::Create(&client);
parent->AddChild(child);
child->SetMaskLayer(mask.get());
@@ -1074,7 +1074,7 @@ class LayerTreeHostFactory {
};
void AssertLayerTreeHostMatchesForSubtree(Layer* layer, LayerTreeHost* host) {
- EXPECT_EQ(host, layer->GetLayerTreeHostForTesting());
+ EXPECT_EQ(host, layer->layer_tree_host());
for (size_t i = 0; i < layer->children().size(); ++i)
AssertLayerTreeHostMatchesForSubtree(layer->children()[i].get(), host);
@@ -1088,7 +1088,8 @@ class LayerLayerTreeHostTest : public testing::Test {};
TEST_F(LayerLayerTreeHostTest, EnteringTree) {
scoped_refptr<Layer> parent = Layer::Create();
scoped_refptr<Layer> child = Layer::Create();
- scoped_refptr<Layer> mask = Layer::Create();
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
// Set up a detached tree of layers. The host pointer should be nil for these
// layers.
@@ -1125,7 +1126,7 @@ TEST_F(LayerLayerTreeHostTest, AddingLayerSubtree) {
layer_tree_host->SetRootLayer(parent.get());
- EXPECT_EQ(parent->GetLayerTreeHostForTesting(), layer_tree_host.get());
+ EXPECT_EQ(parent->layer_tree_host(), layer_tree_host.get());
// Adding a subtree to a layer already associated with a host should set the
// host pointer on all layers in that subtree.
@@ -1134,7 +1135,8 @@ TEST_F(LayerLayerTreeHostTest, AddingLayerSubtree) {
child->AddChild(grand_child);
// Masks should pick up the new host too.
- scoped_refptr<Layer> child_mask = Layer::Create();
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> child_mask = PictureLayer::Create(&client);
child->SetMaskLayer(child_mask.get());
parent->AddChild(child);
@@ -1146,7 +1148,8 @@ TEST_F(LayerLayerTreeHostTest, AddingLayerSubtree) {
TEST_F(LayerLayerTreeHostTest, ChangeHost) {
scoped_refptr<Layer> parent = Layer::Create();
scoped_refptr<Layer> child = Layer::Create();
- scoped_refptr<Layer> mask = Layer::Create();
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
// Same setup as the previous test.
parent->AddChild(child);
@@ -1205,10 +1208,9 @@ TEST_F(LayerLayerTreeHostTest, ChangeHostInSubtree) {
second_parent->AddChild(second_child);
// The moved layer and its children should point to the new host.
+ EXPECT_EQ(second_layer_tree_host.get(), second_child->layer_tree_host());
EXPECT_EQ(second_layer_tree_host.get(),
- second_child->GetLayerTreeHostForTesting());
- EXPECT_EQ(second_layer_tree_host.get(),
- second_grand_child->GetLayerTreeHostForTesting());
+ second_grand_child->layer_tree_host());
// Test over, cleanup time.
first_layer_tree_host->SetRootLayer(nullptr);
@@ -1216,10 +1218,12 @@ TEST_F(LayerLayerTreeHostTest, ChangeHostInSubtree) {
}
TEST_F(LayerLayerTreeHostTest, ReplaceMaskLayer) {
+ FakeContentLayerClient client;
+
scoped_refptr<Layer> parent = Layer::Create();
- scoped_refptr<Layer> mask = Layer::Create();
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
scoped_refptr<Layer> mask_child = Layer::Create();
- scoped_refptr<Layer> mask_replacement = Layer::Create();
+ scoped_refptr<PictureLayer> mask_replacement = PictureLayer::Create(&client);
parent->SetMaskLayer(mask.get());
mask->AddChild(mask_child);
@@ -1234,8 +1238,8 @@ TEST_F(LayerLayerTreeHostTest, ReplaceMaskLayer) {
// Replacing the mask should clear out the old mask's subtree's host pointers.
parent->SetMaskLayer(mask_replacement.get());
- EXPECT_EQ(nullptr, mask->GetLayerTreeHostForTesting());
- EXPECT_EQ(nullptr, mask_child->GetLayerTreeHostForTesting());
+ EXPECT_EQ(nullptr, mask->layer_tree_host());
+ EXPECT_EQ(nullptr, mask_child->layer_tree_host());
// Test over, cleanup time.
layer_tree_host->SetRootLayer(nullptr);
diff --git a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
index 385b044e2f4..bd853412370 100644
--- a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -50,7 +50,7 @@ void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size,
FakeUIResourceLayerTreeHostImpl host_impl(&task_runner_provider,
&task_graph_runner);
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
std::unique_ptr<NinePatchLayerImpl> layer =
NinePatchLayerImpl::Create(host_impl.active_tree(), 1);
@@ -115,6 +115,8 @@ void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size,
} else {
EXPECT_TRUE(layer_remaining.bounds().IsEmpty());
}
+
+ host_impl.DeleteUIResource(uid);
}
void NinePatchLayerLayoutTestWithOcclusion(const gfx::Size& bitmap_size,
@@ -161,7 +163,7 @@ void NinePatchLayerLayoutTestWithOcclusion(const gfx::Size& bitmap_size,
FakeUIResourceLayerTreeHostImpl host_impl(&task_runner_provider,
&task_graph_runner);
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
std::unique_ptr<NinePatchLayerImpl> layer =
NinePatchLayerImpl::Create(host_impl.active_tree(), 1);
@@ -218,6 +220,8 @@ void NinePatchLayerLayoutTestWithOcclusion(const gfx::Size& bitmap_size,
EXPECT_EQ(expected_tex_remaining, tex_remaining.bounds());
Region aperture_region(expected_tex_remaining);
EXPECT_EQ(aperture_region, tex_remaining);
+
+ host_impl.DeleteUIResource(uid);
}
TEST(NinePatchLayerImplTest, VerifyDrawQuads) {
diff --git a/chromium/cc/layers/nine_patch_layer_unittest.cc b/chromium/cc/layers/nine_patch_layer_unittest.cc
index 969de99e8cf..6ec1d95ac1d 100644
--- a/chromium/cc/layers/nine_patch_layer_unittest.cc
+++ b/chromium/cc/layers/nine_patch_layer_unittest.cc
@@ -51,7 +51,7 @@ TEST_F(NinePatchLayerTest, SetLayerProperties) {
layer_tree_host_->SetRootLayer(test_layer);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
- EXPECT_EQ(test_layer->GetLayerTreeHostForTesting(), layer_tree_host_.get());
+ EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get());
test_layer->Update();
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
index acb02addf13..8bea0f87987 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
@@ -97,10 +97,6 @@ void PaintedOverlayScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
scrollbar_layer->set_track_ui_resource_id(0);
}
-ScrollbarLayerInterface* PaintedOverlayScrollbarLayer::ToScrollbarLayer() {
- return this;
-}
-
void PaintedOverlayScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
// When the LTH is set to null or has changed, then this layer should remove
// all of its associated resources.
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.h b/chromium/cc/layers/painted_overlay_scrollbar_layer.h
index 7f4c555d6ce..674a7266f71 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer.h
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.h
@@ -25,7 +25,6 @@ class CC_EXPORT PaintedOverlayScrollbarLayer : public ScrollbarLayerInterface,
ElementId scroll_element_id = ElementId());
bool OpacityCanAnimateOnImplThread() const override;
- ScrollbarLayerInterface* ToScrollbarLayer() override;
// ScrollbarLayerInterface
void SetScrollElementId(ElementId element_id) override;
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
index 4f5a61eb060..831dffcf63c 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
@@ -64,7 +64,7 @@ void PaintedOverlayScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
bool PaintedOverlayScrollbarLayerImpl::WillDraw(
DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) {
+ viz::ClientResourceProvider* resource_provider) {
DCHECK(draw_mode != DRAW_MODE_RESOURCELESS_SOFTWARE);
return LayerImpl::WillDraw(draw_mode, resource_provider);
}
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h
index ca436bd40b9..37bdce9eda1 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h
@@ -31,7 +31,7 @@ class CC_EXPORT PaintedOverlayScrollbarLayerImpl
void PushPropertiesTo(LayerImpl* layer) override;
bool WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) override;
+ viz::ClientResourceProvider* resource_provider) override;
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc
index c510444b898..db2867dc4a9 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc
@@ -61,8 +61,7 @@ TEST(PaintedOverlayScrollbarLayerTest, PaintTickmarks) {
scrollbar_layer->SetBounds(gfx::Size(100, 100));
layer_tree_host->SetRootLayer(scrollbar_layer);
- EXPECT_EQ(scrollbar_layer->GetLayerTreeHostForTesting(),
- layer_tree_host.get());
+ EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host.get());
// Request no paint when initialization.
scrollbar_layer->Update();
diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc
index 52a2b0b7911..cf65df0e6e2 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer.cc
@@ -109,10 +109,6 @@ void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
scrollbar_layer->set_is_overlay_scrollbar(is_overlay_);
}
-ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() {
- return this;
-}
-
void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
// When the LTH is set to null or has changed, then this layer should remove
// all of its associated resources.
diff --git a/chromium/cc/layers/painted_scrollbar_layer.h b/chromium/cc/layers/painted_scrollbar_layer.h
index f55db7b8f7f..6f293bf5029 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.h
+++ b/chromium/cc/layers/painted_scrollbar_layer.h
@@ -25,7 +25,6 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
ElementId element_id = ElementId());
bool OpacityCanAnimateOnImplThread() const override;
- ScrollbarLayerInterface* ToScrollbarLayer() override;
// ScrollbarLayerInterface
void SetScrollElementId(ElementId element_id) override;
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
index 758cf62d163..912e2a0a322 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
@@ -79,7 +79,7 @@ void PaintedScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
bool PaintedScrollbarLayerImpl::WillDraw(
DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) {
+ viz::ClientResourceProvider* resource_provider) {
DCHECK(draw_mode != DRAW_MODE_RESOURCELESS_SOFTWARE);
return LayerImpl::WillDraw(draw_mode, resource_provider);
}
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.h b/chromium/cc/layers/painted_scrollbar_layer_impl.h
index a08bfb3d161..a76b642f30e 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.h
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.h
@@ -30,7 +30,7 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase {
void PushPropertiesTo(LayerImpl* layer) override;
bool WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) override;
+ viz::ClientResourceProvider* resource_provider) override;
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
gfx::Rect GetEnclosingRectInTargetSpace() const override;
diff --git a/chromium/cc/layers/painted_scrollbar_layer_unittest.cc b/chromium/cc/layers/painted_scrollbar_layer_unittest.cc
index f4767910181..53ce3fabcef 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_unittest.cc
@@ -43,8 +43,7 @@ TEST(PaintedScrollbarLayerTest, NeedsPaint) {
scrollbar_layer->SetBounds(gfx::Size(100, 100));
layer_tree_host->SetRootLayer(scrollbar_layer);
- EXPECT_EQ(scrollbar_layer->GetLayerTreeHostForTesting(),
- layer_tree_host.get());
+ EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host.get());
// Request no paint, but expect them to be painted because they have not
// yet been initialized.
diff --git a/chromium/cc/layers/picture_layer.h b/chromium/cc/layers/picture_layer.h
index b4d2f7abb27..bbf460b94f9 100644
--- a/chromium/cc/layers/picture_layer.h
+++ b/chromium/cc/layers/picture_layer.h
@@ -38,13 +38,10 @@ class CC_EXPORT PictureLayer : public Layer {
void SetLayerTreeHost(LayerTreeHost* host) override;
void PushPropertiesTo(LayerImpl* layer) override;
void SetNeedsDisplayRect(const gfx::Rect& layer_rect) override;
- bool Update() override;
- void SetLayerMaskType(LayerMaskType mask_type) override;
sk_sp<SkPicture> GetPicture() const override;
-
+ bool Update() override;
bool HasSlowPaths() const override;
bool HasNonAAPaint() const override;
-
void RunMicroBenchmark(MicroBenchmark* benchmark) override;
ContentLayerClient* client() { return picture_layer_inputs_.client; }
@@ -55,6 +52,7 @@ class CC_EXPORT PictureLayer : public Layer {
const DisplayItemList* GetDisplayItemList();
+ void SetLayerMaskType(LayerMaskType mask_type);
LayerMaskType mask_type() { return mask_type_; }
protected:
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index 4dc5f16985f..56bca3794d3 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -336,10 +336,23 @@ void PictureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
gfx::Size texture_size = quad_content_rect.size();
gfx::RectF texture_rect = gfx::RectF(gfx::SizeF(texture_size));
+ viz::PictureDrawQuad::ImageAnimationMap image_animation_map;
+ const auto* controller = layer_tree_impl()->image_animation_controller();
+ WhichTree tree = layer_tree_impl()->IsPendingTree()
+ ? WhichTree::PENDING_TREE
+ : WhichTree::ACTIVE_TREE;
+ for (const auto& image_data : raster_source_->GetDisplayItemList()
+ ->discardable_image_map()
+ .animated_images_metadata()) {
+ image_animation_map[image_data.paint_image_id] =
+ controller->GetFrameIndexForImage(image_data.paint_image_id, tree);
+ }
+
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::PictureDrawQuad>();
quad->SetNew(shared_quad_state, geometry_rect, visible_geometry_rect,
needs_blending, texture_rect, texture_size, nearest_neighbor_,
viz::RGBA_8888, quad_content_rect, max_contents_scale,
+ std::move(image_animation_map),
raster_source_->GetDisplayItemList());
ValidateQuadResources(quad);
return;
diff --git a/chromium/cc/layers/picture_layer_impl_perftest.cc b/chromium/cc/layers/picture_layer_impl_perftest.cc
index e633f9bdfe6..fa1a8571c9a 100644
--- a/chromium/cc/layers/picture_layer_impl_perftest.cc
+++ b/chromium/cc/layers/picture_layer_impl_perftest.cc
@@ -52,7 +52,7 @@ class PictureLayerImplPerfTest : public testing::Test {
void SetUp() override {
host_impl_.SetVisible(true);
- host_impl_.InitializeRenderer(layer_tree_frame_sink_.get());
+ host_impl_.InitializeFrameSink(layer_tree_frame_sink_.get());
}
void SetupPendingTree(const gfx::Size& layer_bounds) {
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index 90f76f90953..05de466c6d7 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -38,7 +38,6 @@
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/tile_draw_quad.h"
#include "components/viz/test/begin_frame_args_test.h"
-#include "components/viz/test/test_web_graphics_context_3d.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -808,7 +807,7 @@ TEST_F(PictureLayerImplTest, PinchGestureTilings) {
EXPECT_NE(LOW_RESOLUTION, low_res_tiling->resolution());
// Stop a pinch gesture.
- host_impl()->PinchGestureEnd(gfx::Point(), true);
+ host_impl()->PinchGestureEnd(gfx::Point(), false);
// Ensure UpdateTiles won't remove any tilings.
active_layer()->MarkAllTilingsUsed();
@@ -938,7 +937,7 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
1.f * low_res_factor,
active_layer()->tilings()->tiling_at(1)->contents_scale_key());
- host_impl()->PinchGestureEnd(gfx::Point(), true);
+ host_impl()->PinchGestureEnd(gfx::Point(), false);
// Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
scale = 1.2f;
@@ -3769,7 +3768,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
active_layer()->CleanUpTilingsOnActiveLayer(used_tilings);
ASSERT_EQ(1u, active_layer()->tilings()->num_tilings());
- host_impl()->PinchGestureEnd(gfx::Point(), true);
+ host_impl()->PinchGestureEnd(gfx::Point(), false);
// Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
scale /= 4.f;
diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc
index 1c92c7e9785..7f2661cbbc8 100644
--- a/chromium/cc/layers/picture_layer_unittest.cc
+++ b/chromium/cc/layers/picture_layer_unittest.cc
@@ -60,7 +60,7 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
FakeLayerTreeFrameSink::CreateSoftware();
FakeLayerTreeHostImpl host_impl(
LayerTreeSettings(), &impl_task_runner_provider, &task_graph_runner);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.CreatePendingTree();
std::unique_ptr<FakePictureLayerImpl> layer_impl =
FakePictureLayerImpl::Create(host_impl.pending_tree(), 1);
@@ -101,7 +101,7 @@ TEST(PictureLayerTest, InvalidateRasterAfterUpdate) {
FakeLayerTreeHostImpl host_impl(
layer_tree_settings, &impl_task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.CreatePendingTree();
host_impl.pending_tree()->SetRootLayerForTesting(
FakePictureLayerImpl::Create(host_impl.pending_tree(), 1));
@@ -142,7 +142,7 @@ TEST(PictureLayerTest, InvalidateRasterWithoutUpdate) {
FakeLayerTreeHostImpl host_impl(
layer_tree_settings, &impl_task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.CreatePendingTree();
host_impl.pending_tree()->SetRootLayerForTesting(
FakePictureLayerImpl::Create(host_impl.pending_tree(), 1));
@@ -187,7 +187,7 @@ TEST(PictureLayerTest, ClearVisibleRectWhenNoTiling) {
FakeLayerTreeHostImpl host_impl(
layer_tree_settings, &impl_task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
- EXPECT_TRUE(host_impl.InitializeRenderer(layer_tree_frame_sink.get()));
+ EXPECT_TRUE(host_impl.InitializeFrameSink(layer_tree_frame_sink.get()));
host_impl.CreatePendingTree();
host_impl.pending_tree()->SetRootLayerForTesting(
diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc
index 02caf7cb7e7..4df28434eb0 100644
--- a/chromium/cc/layers/render_surface_impl.cc
+++ b/chromium/cc/layers/render_surface_impl.cc
@@ -616,7 +616,10 @@ void RenderSurfaceImpl::TileMaskLayer(
case viz::DrawQuad::SOLID_COLOR: {
SkColor temp_color =
viz::SolidColorDrawQuad::MaterialCast(temp_quad)->color;
- if (!temp_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);
diff --git a/chromium/cc/layers/render_surface_unittest.cc b/chromium/cc/layers/render_surface_unittest.cc
index 14f74ecc27e..22175731c7c 100644
--- a/chromium/cc/layers/render_surface_unittest.cc
+++ b/chromium/cc/layers/render_surface_unittest.cc
@@ -98,7 +98,7 @@ TEST(RenderSurfaceTest, VerifySurfaceChangesAreTrackedProperly) {
host_impl.active_tree()->ResetAllChangeTracking();
host_impl.active_tree()->SetRootLayerForTesting(std::move(owning_layer));
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl.active_tree()->UpdateDrawProperties();
@@ -158,7 +158,7 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectSharedQuadState) {
root_layer->test_properties()->AddChild(std::move(owning_layer));
host_impl.active_tree()->SetRootLayerForTesting(std::move(root_layer));
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl.active_tree()->UpdateDrawProperties();
@@ -216,7 +216,7 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectRenderPass) {
root_layer->test_properties()->AddChild(std::move(owning_layer));
host_impl.active_tree()->SetRootLayerForTesting(std::move(root_layer));
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl.active_tree()->UpdateDrawProperties();
@@ -272,7 +272,7 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceDropsOccludedRenderPassDrawQuads) {
root_layer->test_properties()->AddChild(std::move(owning_layer));
host_impl.active_tree()->SetRootLayerForTesting(std::move(root_layer));
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl.active_tree()->UpdateDrawProperties();
@@ -341,7 +341,7 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceIgnoreMaskLayerOcclusion) {
root_layer->test_properties()->AddChild(std::move(owning_layer));
host_impl.active_tree()->SetRootLayerForTesting(std::move(root_layer));
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl.active_tree()->UpdateDrawProperties();
diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc
index 131182ac2d0..f90363297e0 100644
--- a/chromium/cc/layers/scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/scrollbar_layer_unittest.cc
@@ -38,7 +38,7 @@
#include "cc/trees/tree_synchronizer.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/test/test_context_provider.h"
-#include "components/viz/test/test_web_graphics_context_3d.h"
+#include "components/viz/test/test_gles2_interface.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -219,7 +219,6 @@ TEST_F(ScrollbarLayerTest, RepaintOverlayWhenResourceDisposed) {
scrollbar_layer->SetBounds(gfx::Size(100, 100));
layer_tree_root->SetBounds(gfx::Size(100, 200));
content_layer->SetBounds(gfx::Size(100, 200));
- scrollbar_layer->set_visible_layer_rect(gfx::Rect(0, 0, 100, 200));
}
// First call to update should create a resource. The scrollbar itself thinks
@@ -965,10 +964,6 @@ TEST_F(AuraScrollbarLayerTest, ScrollbarLayerCreateAfterSetScrollable) {
layer_tree_host_->CommitAndCreatePendingTree();
host_impl->ActivateSyncTree();
- LayerImpl* scroll_layer_impl =
- host_impl->active_tree()->LayerByElementId(scroll_layer->element_id());
- EXPECT_TRUE(scroll_layer_impl->needs_show_scrollbars());
-
std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
scoped_refptr<Layer> scrollbar_layer = SolidColorScrollbarLayer::Create(
scrollbar->Orientation(), kThumbThickness, kTrackStart,
@@ -1124,11 +1119,9 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
layer_tree_root->SetScrollOffset(gfx::ScrollOffset(10, 20));
layer_tree_root->SetBounds(gfx::Size(100, 200));
content_layer->SetBounds(gfx::Size(100, 200));
- scrollbar_layer->set_visible_layer_rect(gfx::Rect(0, 0, 100, 200));
testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
- EXPECT_EQ(scrollbar_layer->GetLayerTreeHostForTesting(),
- layer_tree_host_.get());
+ EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
for (int update_counter = 0; update_counter < num_updates; update_counter++)
scrollbar_layer->Update();
@@ -1183,11 +1176,9 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
scrollbar_layer->SetPosition(gfx::PointF(scrollbar_location));
layer_tree_root->SetBounds(gfx::Size(100, 200));
content_layer->SetBounds(gfx::Size(100, 200));
- scrollbar_layer->set_visible_layer_rect(gfx::Rect(0, 0, 100, 200));
testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
- EXPECT_EQ(scrollbar_layer->GetLayerTreeHostForTesting(),
- layer_tree_host_.get());
+ EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
size_t resource_count;
int expected_created, expected_deleted;
@@ -1310,7 +1301,10 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
EXPECT_EQ(gfx::Size(90, 15), fake_ui_resource_manager_->ui_resource_size(
scrollbar_layer->track_resource_id()));
- scrollbar_layer->ResetNeedsDisplayForTesting();
+ // Simulate commit to compositor thread.
+ scrollbar_layer->PushPropertiesTo(
+ scrollbar_layer->CreateLayerImpl(layer_tree_host_->active_tree()).get());
+
EXPECT_FALSE(scrollbar_layer->Update());
EXPECT_NE(0, scrollbar_layer->track_resource_id());
EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
@@ -1343,11 +1337,8 @@ class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
scrollbar_layer->SetPosition(gfx::PointF(scrollbar_location));
layer_tree_root->SetBounds(gfx::Size(100, 200));
content_layer->SetBounds(gfx::Size(100, 200));
- scrollbar_layer->set_visible_layer_rect(
- gfx::Rect(scrollbar_location, scrollbar_layer->bounds()));
- EXPECT_EQ(scrollbar_layer->GetLayerTreeHostForTesting(),
- layer_tree_host_.get());
+ EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
layer_tree_host_->SetViewportSizeAndScale(
layer_tree_host_->device_viewport_size(), test_scale,
@@ -1387,7 +1378,7 @@ TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
viz::TestContextProvider::Create();
// Keep the max texture size reasonable so we don't OOM on low end devices
// (crbug.com/642333).
- context->UnboundTestContext3d()->set_max_texture_size(512);
+ context->UnboundTestContextGL()->set_max_texture_size(512);
context->BindToCurrentThread();
int max_texture_size = 0;
context->ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
@@ -1413,7 +1404,6 @@ class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
scrollbar_layer->SetPosition(gfx::PointF(scrollbar_rect.origin()));
scrollbar_layer->fake_scrollbar()->set_location(scrollbar_rect.origin());
scrollbar_layer->fake_scrollbar()->set_track_rect(scrollbar_rect);
- scrollbar_layer->set_visible_layer_rect(scrollbar_rect);
layer_tree_host_->SetViewportSizeAndScale(
layer_tree_host_->device_viewport_size(), test_scale,
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.cc b/chromium/cc/layers/solid_color_scrollbar_layer.cc
index 6f4e2e23f84..f514b6dd762 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer.cc
+++ b/chromium/cc/layers/solid_color_scrollbar_layer.cc
@@ -64,10 +64,6 @@ SolidColorScrollbarLayer::SolidColorScrollbarLayer(
SolidColorScrollbarLayer::~SolidColorScrollbarLayer() = default;
-ScrollbarLayerInterface* SolidColorScrollbarLayer::ToScrollbarLayer() {
- return this;
-}
-
void SolidColorScrollbarLayer::SetOpacity(float opacity) {
// The opacity of a solid color scrollbar layer is always 0 on main thread.
DCHECK_EQ(opacity, 0.f);
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.h b/chromium/cc/layers/solid_color_scrollbar_layer.h
index 3ff721f6740..69bcc4f1440 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer.h
+++ b/chromium/cc/layers/solid_color_scrollbar_layer.h
@@ -26,7 +26,6 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface,
// Layer overrides.
bool OpacityCanAnimateOnImplThread() const override;
- ScrollbarLayerInterface* ToScrollbarLayer() override;
void SetOpacity(float opacity) override;
void PushPropertiesTo(LayerImpl* layer) override;
diff --git a/chromium/cc/layers/surface_layer.cc b/chromium/cc/layers/surface_layer.cc
index 6124fe42fbf..4940951b840 100644
--- a/chromium/cc/layers/surface_layer.cc
+++ b/chromium/cc/layers/surface_layer.cc
@@ -17,8 +17,19 @@ scoped_refptr<SurfaceLayer> SurfaceLayer::Create() {
return base::WrapRefCounted(new SurfaceLayer());
}
+scoped_refptr<SurfaceLayer> SurfaceLayer::Create(
+ UpdateSubmissionStateCB update_submission_state_callback) {
+ return base::WrapRefCounted(
+ new SurfaceLayer(std::move(update_submission_state_callback)));
+}
+
SurfaceLayer::SurfaceLayer() = default;
+SurfaceLayer::SurfaceLayer(
+ UpdateSubmissionStateCB update_submission_state_callback)
+ : update_submission_state_callback_(
+ std::move(update_submission_state_callback)) {}
+
SurfaceLayer::~SurfaceLayer() {
DCHECK(!layer_tree_host());
}
@@ -29,24 +40,61 @@ void SurfaceLayer::SetPrimarySurfaceId(const viz::SurfaceId& surface_id,
deadline_policy.use_existing_deadline()) {
return;
}
+
+ TRACE_EVENT_WITH_FLOW2(
+ TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
+ "LocalSurfaceId.Embed.Flow",
+ TRACE_ID_GLOBAL(surface_id.local_surface_id().embed_trace_id()),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
+ "SetPrimarySurfaceId", "surface_id", surface_id.ToString());
+
+ const viz::SurfaceRange old_surface_range(GetSurfaceRange());
+ if (layer_tree_host() && old_surface_range.IsValid())
+ layer_tree_host()->RemoveSurfaceRange(old_surface_range);
+
primary_surface_id_ = surface_id;
- if (!deadline_policy.use_existing_deadline())
+
+ const viz::SurfaceRange new_surface_range(GetSurfaceRange());
+ if (layer_tree_host() && new_surface_range.IsValid())
+ layer_tree_host()->AddSurfaceRange(new_surface_range);
+
+ // We should never block or set a deadline on an invalid
+ // |primary_surface_id_|.
+ if (!primary_surface_id_.is_valid()) {
+ deadline_in_frames_ = 0u;
+ } else if (!deadline_policy.use_existing_deadline()) {
deadline_in_frames_ = deadline_policy.deadline_in_frames();
+ }
UpdateDrawsContent(HasDrawableContent());
SetNeedsCommit();
}
void SurfaceLayer::SetFallbackSurfaceId(const viz::SurfaceId& surface_id) {
- if (fallback_surface_id_ == surface_id)
+ if (fallback_surface_id_ == surface_id) {
+ // TODO(samans): This was added to fix https://crbug.com/827242. Remove this
+ // once fallback SurfaceIds aren't tied to SurfaceReferences, and
+ // viz::Display can handle missing fallbacks. https://crbug.com/857575
+ if (layer_tree_host())
+ layer_tree_host()->SetNeedsCommitWithForcedRedraw();
return;
+ }
- if (layer_tree_host())
- layer_tree_host()->RemoveSurfaceLayerId(fallback_surface_id_);
+ TRACE_EVENT_WITH_FLOW2(
+ TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
+ "LocalSurfaceId.Submission.Flow",
+ TRACE_ID_GLOBAL(surface_id.local_surface_id().submission_trace_id()),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
+ "SetFallbackSurfaceId", "surface_id", surface_id.ToString());
+
+ const viz::SurfaceRange old_surface_range(GetSurfaceRange());
+ if (layer_tree_host() && old_surface_range.IsValid())
+ layer_tree_host()->RemoveSurfaceRange(old_surface_range);
fallback_surface_id_ = surface_id;
- if (layer_tree_host() && fallback_surface_id_.is_valid())
- layer_tree_host()->AddSurfaceLayerId(fallback_surface_id_);
+ const viz::SurfaceRange new_surface_range(GetSurfaceRange());
+ if (layer_tree_host() && new_surface_range.IsValid())
+ layer_tree_host()->AddSurfaceRange(new_surface_range);
SetNeedsCommit();
}
@@ -66,9 +114,16 @@ void SurfaceLayer::SetSurfaceHitTestable(bool surface_hit_testable) {
SetNeedsPushProperties();
}
+void SurfaceLayer::SetMayContainVideo(bool may_contain_video) {
+ may_contain_video_ = may_contain_video;
+}
+
std::unique_ptr<LayerImpl> SurfaceLayer::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return SurfaceLayerImpl::Create(tree_impl, id());
+ auto layer_impl = SurfaceLayerImpl::Create(tree_impl, id(),
+ update_submission_state_callback_);
+ layer_impl->set_may_contain_video(may_contain_video_);
+ return layer_impl;
}
bool SurfaceLayer::HasDrawableContent() const {
@@ -79,14 +134,15 @@ void SurfaceLayer::SetLayerTreeHost(LayerTreeHost* host) {
if (layer_tree_host() == host) {
return;
}
-
- if (layer_tree_host() && fallback_surface_id_.is_valid())
- layer_tree_host()->RemoveSurfaceLayerId(fallback_surface_id_);
+ const viz::SurfaceRange old_surface_range(GetSurfaceRange());
+ if (layer_tree_host() && old_surface_range.IsValid())
+ layer_tree_host()->RemoveSurfaceRange(old_surface_range);
Layer::SetLayerTreeHost(host);
- if (layer_tree_host() && fallback_surface_id_.is_valid())
- layer_tree_host()->AddSurfaceLayerId(fallback_surface_id_);
+ const viz::SurfaceRange new_surface_range(GetSurfaceRange());
+ if (layer_tree_host() && new_surface_range.IsValid())
+ layer_tree_host()->AddSurfaceRange(new_surface_range);
}
void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) {
@@ -103,4 +159,13 @@ void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) {
layer_impl->SetSurfaceHitTestable(surface_hit_testable_);
}
+viz::SurfaceRange SurfaceLayer::GetSurfaceRange() const {
+ return viz::SurfaceRange(
+ fallback_surface_id_.is_valid()
+ ? base::Optional<viz::SurfaceId>(fallback_surface_id_)
+ : base::nullopt,
+ primary_surface_id_.is_valid() ? primary_surface_id_
+ : fallback_surface_id_);
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/surface_layer.h b/chromium/cc/layers/surface_layer.h
index 87c5a26dfe2..863f7bd7654 100644
--- a/chromium/cc/layers/surface_layer.h
+++ b/chromium/cc/layers/surface_layer.h
@@ -10,16 +10,22 @@
#include "cc/layers/deadline_policy.h"
#include "cc/layers/layer.h"
#include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/common/surfaces/surface_range.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
+// If given true, we should submit frames, as we are unoccluded on screen.
+// If given false, we should not submit compositor frames.
+using UpdateSubmissionStateCB = base::RepeatingCallback<void(bool is_visible)>;
+
// A layer that renders a surface referencing the output of another compositor
// instance or client.
class CC_EXPORT SurfaceLayer : public Layer {
public:
static scoped_refptr<SurfaceLayer> Create();
+ static scoped_refptr<SurfaceLayer> Create(UpdateSubmissionStateCB);
void SetPrimarySurfaceId(const viz::SurfaceId& surface_id,
const DeadlinePolicy& deadline_policy);
@@ -35,6 +41,8 @@ class CC_EXPORT SurfaceLayer : public Layer {
void SetSurfaceHitTestable(bool surface_hit_testable);
bool surface_hit_testable() const { return surface_hit_testable_; }
+ void SetMayContainVideo(bool);
+
// Layer overrides.
std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
void SetLayerTreeHost(LayerTreeHost* host) override;
@@ -54,11 +62,18 @@ class CC_EXPORT SurfaceLayer : public Layer {
protected:
SurfaceLayer();
+ explicit SurfaceLayer(UpdateSubmissionStateCB);
bool HasDrawableContent() const override;
private:
~SurfaceLayer() override;
+ // Returns a SurfaceRange corresponding to the surface layer.
+ viz::SurfaceRange GetSurfaceRange() const;
+
+ UpdateSubmissionStateCB update_submission_state_callback_;
+
+ bool may_contain_video_ = false;
viz::SurfaceId primary_surface_id_;
viz::SurfaceId fallback_surface_id_;
base::Optional<uint32_t> deadline_in_frames_ = 0u;
diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc
index def5281514d..1f9aa257247 100644
--- a/chromium/cc/layers/surface_layer_impl.cc
+++ b/chromium/cc/layers/surface_layer_impl.cc
@@ -16,14 +16,23 @@
namespace cc {
-SurfaceLayerImpl::SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id)
- : LayerImpl(tree_impl, id) {}
-
-SurfaceLayerImpl::~SurfaceLayerImpl() = default;
+SurfaceLayerImpl::SurfaceLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ UpdateSubmissionStateCB update_submission_state_callback)
+ : LayerImpl(tree_impl, id),
+ update_submission_state_callback_(
+ std::move(update_submission_state_callback)) {}
+
+SurfaceLayerImpl::~SurfaceLayerImpl() {
+ if (update_submission_state_callback_)
+ update_submission_state_callback_.Run(false);
+}
std::unique_ptr<LayerImpl> SurfaceLayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return SurfaceLayerImpl::Create(tree_impl, id());
+ return SurfaceLayerImpl::Create(tree_impl, id(),
+ std::move(update_submission_state_callback_));
}
void SurfaceLayerImpl::SetPrimarySurfaceId(
@@ -33,6 +42,14 @@ void SurfaceLayerImpl::SetPrimarySurfaceId(
deadline_in_frames_ == deadline_in_frames) {
return;
}
+
+ TRACE_EVENT_WITH_FLOW2(
+ TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
+ "LocalSurfaceId.Embed.Flow",
+ TRACE_ID_GLOBAL(surface_id.local_surface_id().embed_trace_id()),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
+ "ImplSetPrimarySurfaceId", "surface_id", surface_id.ToString());
+
primary_surface_id_ = surface_id;
deadline_in_frames_ = deadline_in_frames;
NoteLayerPropertyChanged();
@@ -42,6 +59,13 @@ void SurfaceLayerImpl::SetFallbackSurfaceId(const viz::SurfaceId& surface_id) {
if (fallback_surface_id_ == surface_id)
return;
+ TRACE_EVENT_WITH_FLOW2(
+ TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
+ "LocalSurfaceId.Submission.Flow",
+ TRACE_ID_GLOBAL(surface_id.local_surface_id().submission_trace_id()),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
+ "ImplSetFallbackSurfaceId", "surface_id", surface_id.ToString());
+
fallback_surface_id_ = surface_id;
NoteLayerPropertyChanged();
}
@@ -74,6 +98,22 @@ void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer_impl->SetSurfaceHitTestable(surface_hit_testable_);
}
+bool SurfaceLayerImpl::WillDraw(
+ DrawMode draw_mode,
+ viz::ClientResourceProvider* resource_provider) {
+ bool will_draw = LayerImpl::WillDraw(draw_mode, resource_provider);
+ // If we have a change in WillDraw (meaning that visibility has changed), we
+ // want to inform the VideoFrameSubmitter to start or stop submitting
+ // compositor frames.
+ if (will_draw_ != will_draw) {
+ will_draw_ = will_draw;
+ if (update_submission_state_callback_)
+ update_submission_state_callback_.Run(will_draw);
+ }
+
+ return primary_surface_id_.is_valid() && will_draw;
+}
+
void SurfaceLayerImpl::AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) {
AppendRainbowDebugBorder(render_pass);
@@ -127,12 +167,8 @@ viz::SurfaceDrawQuad* SurfaceLayerImpl::CreateSurfaceDrawQuad(
if (visible_quad_rect.IsEmpty())
return nullptr;
- // If a |common_shared_quad_state| is provided then use that. Otherwise,
- // allocate a new SharedQuadState. Assign the new SharedQuadState to
- // *|common_shared_quad_state| so that it may be reused by another emitted
- // viz::SurfaceDrawQuad.
viz::SharedQuadState* shared_quad_state =
- shared_quad_state = render_pass->CreateAndAppendSharedQuadState();
+ render_pass->CreateAndAppendSharedQuadState();
PopulateScaledSharedQuadState(shared_quad_state, device_scale_factor,
device_scale_factor, contents_opaque());
diff --git a/chromium/cc/layers/surface_layer_impl.h b/chromium/cc/layers/surface_layer_impl.h
index ce243205514..d283f73e55f 100644
--- a/chromium/cc/layers/surface_layer_impl.h
+++ b/chromium/cc/layers/surface_layer_impl.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "cc/cc_export.h"
@@ -17,12 +18,25 @@
namespace cc {
+// This must match SurfaceLayer::UpdateSubmissionStateCB.
+using UpdateSubmissionStateCB = base::RepeatingCallback<void(bool is_visible)>;
+
class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
public:
+ static std::unique_ptr<SurfaceLayerImpl> Create(
+ LayerTreeImpl* tree_impl,
+ int id,
+ UpdateSubmissionStateCB update_submission_state_callback) {
+ return base::WrapUnique(new SurfaceLayerImpl(
+ tree_impl, id, std::move(update_submission_state_callback)));
+ }
+
static std::unique_ptr<SurfaceLayerImpl> Create(LayerTreeImpl* tree_impl,
int id) {
- return base::WrapUnique(new SurfaceLayerImpl(tree_impl, id));
+ return base::WrapUnique(
+ new SurfaceLayerImpl(tree_impl, id, base::BindRepeating([](bool) {})));
}
+
~SurfaceLayerImpl() override;
void SetPrimarySurfaceId(const viz::SurfaceId& surface_id,
@@ -56,12 +70,14 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
// LayerImpl overrides.
std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
void PushPropertiesTo(LayerImpl* layer) override;
+ bool WillDraw(DrawMode draw_mode,
+ viz::ClientResourceProvider* resource_provider) override;
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
bool is_surface_layer() const override;
protected:
- SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id);
+ SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id, UpdateSubmissionStateCB);
private:
viz::SurfaceDrawQuad* CreateSurfaceDrawQuad(
@@ -74,12 +90,14 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
void AsValueInto(base::trace_event::TracedValue* dict) const override;
const char* LayerTypeAsString() const override;
+ UpdateSubmissionStateCB update_submission_state_callback_;
viz::SurfaceId primary_surface_id_;
viz::SurfaceId fallback_surface_id_;
base::Optional<uint32_t> deadline_in_frames_;
bool stretch_content_to_fill_bounds_ = false;
bool surface_hit_testable_ = false;
+ bool will_draw_ = false;
DISALLOW_COPY_AND_ASSIGN(SurfaceLayerImpl);
};
diff --git a/chromium/cc/layers/surface_layer_impl_unittest.cc b/chromium/cc/layers/surface_layer_impl_unittest.cc
index d8a5f6bcb97..36a57d20ecb 100644
--- a/chromium/cc/layers/surface_layer_impl_unittest.cc
+++ b/chromium/cc/layers/surface_layer_impl_unittest.cc
@@ -44,6 +44,7 @@ TEST(SurfaceLayerImplTest, Occlusion) {
LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
gfx::Rect(layer_size));
EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_TRUE(surface_layer_impl->WillDraw(DRAW_MODE_HARDWARE, nullptr));
}
{
@@ -53,6 +54,7 @@ TEST(SurfaceLayerImplTest, Occlusion) {
LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
EXPECT_EQ(impl.quad_list().size(), 0u);
+ EXPECT_FALSE(surface_layer_impl->WillDraw(DRAW_MODE_HARDWARE, nullptr));
}
{
@@ -66,6 +68,7 @@ TEST(SurfaceLayerImplTest, Occlusion) {
// The layer outputs one quad, which is partially occluded.
EXPECT_EQ(1u, impl.quad_list().size());
EXPECT_EQ(1u, partially_occluded_count);
+ EXPECT_TRUE(surface_layer_impl->WillDraw(DRAW_MODE_HARDWARE, nullptr));
}
}
diff --git a/chromium/cc/layers/surface_layer_unittest.cc b/chromium/cc/layers/surface_layer_unittest.cc
index 9eb987a0f9e..c6e8f16bd7e 100644
--- a/chromium/cc/layers/surface_layer_unittest.cc
+++ b/chromium/cc/layers/surface_layer_unittest.cc
@@ -4,6 +4,7 @@
#include <stdint.h>
+#include <iostream>
#include <set>
#include <vector>
@@ -46,7 +47,7 @@ class SurfaceLayerTest : public testing::Test {
void SynchronizeTrees() {
TreeSynchronizer::PushLayerProperties(layer_tree_host_.get(),
host_impl_.pending_tree());
- layer_tree_host_->PushSurfaceIdsTo(host_impl_.pending_tree());
+ layer_tree_host_->PushSurfaceRangesTo(host_impl_.pending_tree());
}
protected:
@@ -98,6 +99,25 @@ TEST_F(SurfaceLayerTest, UseInfiniteDeadlineForNewSurfaceLayer) {
EXPECT_EQ(std::numeric_limits<uint32_t>::max(), layer->deadline_in_frames());
}
+// This test verifies that if an invalid primary surface ID is set then the
+// deadline will be reset to 0 frames.
+TEST_F(SurfaceLayerTest, ResetDeadlineOnInvalidSurfaceId) {
+ scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create();
+ layer_tree_host_->SetRootLayer(layer);
+ viz::SurfaceId primary_id(
+ kArbitraryFrameSinkId,
+ viz::LocalSurfaceId(1, base::UnguessableToken::Create()));
+ layer->SetPrimarySurfaceId(primary_id,
+ DeadlinePolicy::UseSpecifiedDeadline(3u));
+ EXPECT_EQ(3u, layer->deadline_in_frames());
+
+ // Reset the surface layer to an invalid SurfaceId. Verify that the deadline
+ // is reset.
+ layer->SetPrimarySurfaceId(viz::SurfaceId(),
+ DeadlinePolicy::UseSpecifiedDeadline(3u));
+ EXPECT_EQ(0u, layer->deadline_in_frames());
+}
+
// This test verifies that SurfaceLayer properties are pushed across to
// SurfaceLayerImpl.
TEST_F(SurfaceLayerTest, PushProperties) {
@@ -115,24 +135,24 @@ TEST_F(SurfaceLayerTest, PushProperties) {
layer->SetBackgroundColor(SK_ColorBLUE);
layer->SetStretchContentToFillBounds(true);
- EXPECT_TRUE(layer_tree_host_->needs_surface_ids_sync());
- EXPECT_EQ(layer_tree_host_->SurfaceLayerIds().size(), 1u);
+ EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync());
+ EXPECT_EQ(layer_tree_host_->SurfaceRanges().size(), 1u);
// Verify that pending tree has no surface ids already.
- EXPECT_FALSE(host_impl_.pending_tree()->needs_surface_ids_sync());
- EXPECT_EQ(host_impl_.pending_tree()->SurfaceLayerIds().size(), 0u);
+ EXPECT_FALSE(host_impl_.pending_tree()->needs_surface_ranges_sync());
+ EXPECT_EQ(host_impl_.pending_tree()->SurfaceRanges().size(), 0u);
std::unique_ptr<SurfaceLayerImpl> layer_impl =
SurfaceLayerImpl::Create(host_impl_.pending_tree(), layer->id());
SynchronizeTrees();
// Verify that pending tree received the surface id and also has
- // needs_surface_ids_sync set to true as it needs to sync with active tree.
- EXPECT_TRUE(host_impl_.pending_tree()->needs_surface_ids_sync());
- EXPECT_EQ(host_impl_.pending_tree()->SurfaceLayerIds().size(), 1u);
+ // needs_surface_ranges_sync set to true as it needs to sync with active tree.
+ EXPECT_TRUE(host_impl_.pending_tree()->needs_surface_ranges_sync());
+ EXPECT_EQ(host_impl_.pending_tree()->SurfaceRanges().size(), 1u);
// Verify we have reset the state on layer tree host.
- EXPECT_FALSE(layer_tree_host_->needs_surface_ids_sync());
+ EXPECT_FALSE(layer_tree_host_->needs_surface_ranges_sync());
// Verify that the primary and fallback SurfaceIds are pushed through.
EXPECT_EQ(primary_id, layer_impl->primary_surface_id());
@@ -145,21 +165,23 @@ TEST_F(SurfaceLayerTest, PushProperties) {
kArbitraryFrameSinkId,
viz::LocalSurfaceId(2, base::UnguessableToken::Create()));
layer->SetFallbackSurfaceId(fallback_id);
+ layer->SetPrimarySurfaceId(fallback_id,
+ DeadlinePolicy::UseExistingDeadline());
layer->SetBackgroundColor(SK_ColorGREEN);
layer->SetStretchContentToFillBounds(false);
// Verify that fallback surface id is not recorded on the layer tree host as
// surface synchronization is not enabled.
- EXPECT_TRUE(layer_tree_host_->needs_surface_ids_sync());
- EXPECT_EQ(layer_tree_host_->SurfaceLayerIds().size(), 1u);
+ EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync());
+ EXPECT_EQ(layer_tree_host_->SurfaceRanges().size(), 1u);
SynchronizeTrees();
- EXPECT_EQ(host_impl_.pending_tree()->SurfaceLayerIds().size(), 1u);
+ EXPECT_EQ(host_impl_.pending_tree()->SurfaceRanges().size(), 1u);
// Verify that the primary viz::SurfaceId stays the same and the new
// fallback viz::SurfaceId is pushed through.
- EXPECT_EQ(primary_id, layer_impl->primary_surface_id());
+ EXPECT_EQ(fallback_id, layer_impl->primary_surface_id());
EXPECT_EQ(fallback_id, layer_impl->fallback_surface_id());
EXPECT_EQ(SK_ColorGREEN, layer_impl->background_color());
// The deadline resets back to 0 (no deadline) after the first commit.
@@ -199,9 +221,10 @@ TEST_F(SurfaceLayerTest, CheckSurfaceReferencesForClonedLayer) {
SynchronizeTrees();
// Verify that only |old_surface_id| is going to be referenced.
- EXPECT_THAT(layer_tree_host_->SurfaceLayerIds(), ElementsAre(old_surface_id));
- EXPECT_THAT(host_impl_.pending_tree()->SurfaceLayerIds(),
- ElementsAre(old_surface_id));
+ EXPECT_THAT(layer_tree_host_->SurfaceRanges(),
+ ElementsAre(viz::SurfaceRange(old_surface_id)));
+ EXPECT_THAT(host_impl_.pending_tree()->SurfaceRanges(),
+ ElementsAre(viz::SurfaceRange(old_surface_id)));
const viz::SurfaceId new_surface_id(
kArbitraryFrameSinkId,
@@ -215,10 +238,12 @@ TEST_F(SurfaceLayerTest, CheckSurfaceReferencesForClonedLayer) {
SynchronizeTrees();
// Verify that both surface ids are going to be referenced.
- EXPECT_THAT(layer_tree_host_->SurfaceLayerIds(),
- ElementsAre(old_surface_id, new_surface_id));
- EXPECT_THAT(host_impl_.pending_tree()->SurfaceLayerIds(),
- ElementsAre(old_surface_id, new_surface_id));
+ EXPECT_THAT(layer_tree_host_->SurfaceRanges(),
+ ElementsAre(viz::SurfaceRange(old_surface_id),
+ viz::SurfaceRange(new_surface_id)));
+ EXPECT_THAT(host_impl_.pending_tree()->SurfaceRanges(),
+ ElementsAre(viz::SurfaceRange(old_surface_id),
+ viz::SurfaceRange(new_surface_id)));
// Unparent the old layer like it's being destroyed at the end of animation.
layer1->SetLayerTreeHost(nullptr);
@@ -226,15 +251,16 @@ TEST_F(SurfaceLayerTest, CheckSurfaceReferencesForClonedLayer) {
SynchronizeTrees();
// Verify that only |new_surface_id| is going to be referenced.
- EXPECT_THAT(layer_tree_host_->SurfaceLayerIds(), ElementsAre(new_surface_id));
- EXPECT_THAT(host_impl_.pending_tree()->SurfaceLayerIds(),
- ElementsAre(new_surface_id));
+ EXPECT_THAT(layer_tree_host_->SurfaceRanges(),
+ ElementsAre(viz::SurfaceRange(new_surface_id)));
+ EXPECT_THAT(host_impl_.pending_tree()->SurfaceRanges(),
+ ElementsAre(viz::SurfaceRange(new_surface_id)));
// Cleanup for destruction.
layer2->SetLayerTreeHost(nullptr);
}
-// This test verifies LayerTreeHost::needs_surface_ids_sync() is correct when
+// This test verifies LayerTreeHost::needs_surface_ranges_sync() is correct when
// there are cloned surface layers.
TEST_F(SurfaceLayerTest, CheckNeedsSurfaceIdsSyncForClonedLayers) {
const viz::SurfaceId surface_id(
@@ -246,17 +272,17 @@ TEST_F(SurfaceLayerTest, CheckNeedsSurfaceIdsSyncForClonedLayers) {
layer1->SetPrimarySurfaceId(surface_id, DeadlinePolicy::UseDefaultDeadline());
layer1->SetFallbackSurfaceId(surface_id);
- // Verify the surface id is in SurfaceLayerIds() and needs_surface_ids_sync()
- // is true.
- EXPECT_TRUE(layer_tree_host_->needs_surface_ids_sync());
- EXPECT_THAT(layer_tree_host_->SurfaceLayerIds(), SizeIs(1));
+ // Verify the surface id is in SurfaceLayerIds() and
+ // needs_surface_ranges_sync() is true.
+ EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync());
+ EXPECT_THAT(layer_tree_host_->SurfaceRanges(), SizeIs(1));
std::unique_ptr<SurfaceLayerImpl> layer_impl1 =
SurfaceLayerImpl::Create(host_impl_.pending_tree(), layer1->id());
SynchronizeTrees();
- // After syncchronizing trees verify needs_surface_ids_sync() is false.
- EXPECT_FALSE(layer_tree_host_->needs_surface_ids_sync());
+ // After syncchronizing trees verify needs_surface_ranges_sync() is false.
+ EXPECT_FALSE(layer_tree_host_->needs_surface_ranges_sync());
// Create the second layer that is a clone of the first.
scoped_refptr<SurfaceLayer> layer2 = SurfaceLayer::Create();
@@ -265,29 +291,30 @@ TEST_F(SurfaceLayerTest, CheckNeedsSurfaceIdsSyncForClonedLayers) {
layer2->SetFallbackSurfaceId(surface_id);
// Verify that after creating the second layer with the same surface id that
- // needs_surface_ids_sync() is still false.
- EXPECT_FALSE(layer_tree_host_->needs_surface_ids_sync());
- EXPECT_THAT(layer_tree_host_->SurfaceLayerIds(), SizeIs(1));
+ // needs_surface_ranges_sync() is still false.
+ EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync());
+ EXPECT_THAT(layer_tree_host_->SurfaceRanges(), SizeIs(1));
std::unique_ptr<SurfaceLayerImpl> layer_impl2 =
SurfaceLayerImpl::Create(host_impl_.pending_tree(), layer2->id());
SynchronizeTrees();
- // Verify needs_surface_ids_sync() is still false after synchronizing trees.
- EXPECT_FALSE(layer_tree_host_->needs_surface_ids_sync());
+ // Verify needs_surface_ranges_sync() is still false after synchronizing
+ // trees.
+ EXPECT_FALSE(layer_tree_host_->needs_surface_ranges_sync());
// Destroy one of the layers, leaving one layer with the surface id.
layer1->SetLayerTreeHost(nullptr);
- // Verify needs_surface_ids_sync() is still false.
- EXPECT_FALSE(layer_tree_host_->needs_surface_ids_sync());
+ // Verify needs_surface_ranges_sync() is still false.
+ EXPECT_FALSE(layer_tree_host_->needs_surface_ranges_sync());
// Destroy the last layer, this should change the set of layer surface ids.
layer2->SetLayerTreeHost(nullptr);
- // Verify SurfaceLayerIds() is empty and needs_surface_ids_sync() is true.
- EXPECT_TRUE(layer_tree_host_->needs_surface_ids_sync());
- EXPECT_THAT(layer_tree_host_->SurfaceLayerIds(), SizeIs(0));
+ // Verify SurfaceLayerIds() is empty and needs_surface_ranges_sync() is true.
+ EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync());
+ EXPECT_THAT(layer_tree_host_->SurfaceRanges(), SizeIs(0));
}
} // namespace
diff --git a/chromium/cc/layers/texture_layer.cc b/chromium/cc/layers/texture_layer.cc
index 359cbf8955d..0b2784bf04d 100644
--- a/chromium/cc/layers/texture_layer.cc
+++ b/chromium/cc/layers/texture_layer.cc
@@ -192,7 +192,12 @@ bool TextureLayer::Update() {
return updated || !update_rect().IsEmpty();
}
-bool TextureLayer::IsSnapped() {
+bool TextureLayer::IsSnappedToPixelGridInTarget() {
+ // Often layers are positioned with CSS to "50%", which can often leave them
+ // with a fractional (N + 0.5) pixel position. This would leave them looking
+ // fuzzy, so we request that TextureLayers are snapped to the pixel grid,
+ // since their content is generated externally and we can not adjust for it
+ // inside the content (unlike for PictureLayers).
return true;
}
diff --git a/chromium/cc/layers/texture_layer.h b/chromium/cc/layers/texture_layer.h
index c8c77755b53..b5d5993179c 100644
--- a/chromium/cc/layers/texture_layer.h
+++ b/chromium/cc/layers/texture_layer.h
@@ -153,7 +153,7 @@ class CC_EXPORT TextureLayer : public Layer, SharedBitmapIdRegistrar {
void SetLayerTreeHost(LayerTreeHost* layer_tree_host) override;
bool Update() override;
- bool IsSnapped() override;
+ bool IsSnappedToPixelGridInTarget() override;
void PushPropertiesTo(LayerImpl* layer) override;
// Request a mapping from SharedBitmapId to SharedMemory be registered via the
diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc
index b0203d5362f..7d34344e47e 100644
--- a/chromium/cc/layers/texture_layer_impl.cc
+++ b/chromium/cc/layers/texture_layer_impl.cc
@@ -42,7 +42,8 @@ std::unique_ptr<LayerImpl> TextureLayerImpl::CreateLayerImpl(
return TextureLayerImpl::Create(tree_impl, id());
}
-bool TextureLayerImpl::IsSnapped() {
+bool TextureLayerImpl::IsSnappedToPixelGridInTarget() {
+ // See TextureLayer::IsSnappedToPixelGridInTarget() for explanation of |true|.
return true;
}
@@ -69,8 +70,9 @@ void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) {
to_unregister_bitmap_ids_.clear();
}
-bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) {
+bool TextureLayerImpl::WillDraw(
+ DrawMode draw_mode,
+ viz::ClientResourceProvider* resource_provider) {
if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
return false;
// These imply some synchronization problem where the compositor is in gpu
@@ -86,6 +88,9 @@ bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
return false;
}
+ if (!LayerImpl::WillDraw(draw_mode, resource_provider))
+ return false;
+
if (own_resource_) {
DCHECK(!resource_id_);
if (!transferable_resource_.mailbox_holder.mailbox.IsZero()) {
@@ -96,7 +101,7 @@ bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
own_resource_ = false;
}
- return resource_id_ && LayerImpl::WillDraw(draw_mode, resource_provider);
+ return resource_id_;
}
void TextureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
@@ -165,9 +170,18 @@ SimpleEnclosedRegion TextureLayerImpl::VisibleOpaqueRegion() const {
return SimpleEnclosedRegion();
}
+void TextureLayerImpl::OnPurgeMemory() {
+ // Do nothing here intentionally as the LayerTreeFrameSink isn't lost.
+ // Unregistering SharedBitmapIds with the LayerTreeFrameSink wouldn't free
+ // the shared memory, as the TextureLayer and/or TextureLayerClient will still
+ // have a reference to it.
+}
+
void TextureLayerImpl::ReleaseResources() {
- FreeTransferableResource();
- resource_id_ = 0;
+ // Gpu resources are lost when the LayerTreeFrameSink is lost. But software
+ // resources are still valid, and we can keep them here in that case.
+ if (!transferable_resource_.is_software)
+ FreeTransferableResource();
// The LayerTreeFrameSink is gone and being replaced, so we will have to
// re-register all SharedBitmapIds on the new LayerTreeFrameSink. We don't
@@ -274,10 +288,6 @@ const char* TextureLayerImpl::LayerTypeAsString() const {
void TextureLayerImpl::FreeTransferableResource() {
if (own_resource_) {
- // TODO(crbug.com/826886): Software resources should be kept alive.
- // if (transferable_resource_.is_software)
- // return;
-
DCHECK(!resource_id_);
if (release_callback_) {
// We didn't use the resource, but the client might need the SyncToken
@@ -288,9 +298,6 @@ void TextureLayerImpl::FreeTransferableResource() {
transferable_resource_ = viz::TransferableResource();
release_callback_ = nullptr;
} else if (resource_id_) {
- // TODO(crbug.com/826886): Ownership of software resources should be
- // reclaimed, including the ReleaseCalback, without running it.
-
DCHECK(!own_resource_);
auto* resource_provider = layer_tree_impl()->resource_provider();
resource_provider->RemoveImportedResource(resource_id_);
diff --git a/chromium/cc/layers/texture_layer_impl.h b/chromium/cc/layers/texture_layer_impl.h
index 49b6be2ffa1..8a75ebccaea 100644
--- a/chromium/cc/layers/texture_layer_impl.h
+++ b/chromium/cc/layers/texture_layer_impl.h
@@ -32,15 +32,16 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
std::unique_ptr<LayerImpl> CreateLayerImpl(
LayerTreeImpl* layer_tree_impl) override;
- bool IsSnapped() override;
+ bool IsSnappedToPixelGridInTarget() override;
void PushPropertiesTo(LayerImpl* layer) override;
bool WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) override;
+ viz::ClientResourceProvider* resource_provider) override;
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
SimpleEnclosedRegion VisibleOpaqueRegion() const override;
void ReleaseResources() override;
+ void OnPurgeMemory() override;
// These setter methods don't cause any implicit damage, so the texture client
// must explicitly invalidate if they intend to cause a visible change in the
@@ -92,13 +93,13 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
// True while the |transferable_resource_| is owned by this layer, and
// becomes false once it is passed to another layer or to the
- // LayerTreeResourceProvider, at which point we get back a |resource_id_|.
+ // viz::ClientResourceProvider, at which point we get back a |resource_id_|.
bool own_resource_ = false;
// A TransferableResource from the layer's client that will be given
// to the display compositor.
viz::TransferableResource transferable_resource_;
// Local ResourceId for the TransferableResource, to be used with the
- // compositor's LayerTreeResourceProvider in order to refer to the
+ // compositor's viz::ClientResourceProvider in order to refer to the
// TransferableResource given to it.
viz::ResourceId resource_id_ = 0;
std::unique_ptr<viz::SingleReleaseCallback> release_callback_;
diff --git a/chromium/cc/layers/texture_layer_impl_unittest.cc b/chromium/cc/layers/texture_layer_impl_unittest.cc
index 2c626ef727c..7022e5757f1 100644
--- a/chromium/cc/layers/texture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/texture_layer_impl_unittest.cc
@@ -52,12 +52,8 @@ TEST(TextureLayerImplTest, Occlusion) {
LayerTestCommon::LayerImplTest impl;
- auto* gl = impl.layer_tree_frame_sink()->context_provider()->ContextGL();
-
- gpu::Mailbox mailbox;
- gl->GenMailboxCHROMIUM(mailbox.name);
auto resource = viz::TransferableResource::MakeGL(
- std::move(mailbox), GL_LINEAR, GL_TEXTURE_2D,
+ gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D,
gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
gpu::CommandBufferId::FromUnsafeValue(0x234), 0x456));
@@ -113,11 +109,9 @@ TEST(TextureLayerImplTest, ResourceNotFreedOnGpuRasterToggle) {
gfx::Size layer_size(1000, 1000);
gfx::Size viewport_size(1000, 1000);
- auto* gl = impl.layer_tree_frame_sink()->context_provider()->ContextGL();
-
viz::TransferableResource resource;
resource.is_software = false;
- gl->GenMailboxCHROMIUM(resource.mailbox_holder.mailbox.name);
+ resource.mailbox_holder.mailbox = gpu::Mailbox::Generate();
resource.mailbox_holder.sync_token =
gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
gpu::CommandBufferId::FromUnsafeValue(0x234), 0x456);
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index 08919e42ed9..66656e3e005 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -39,9 +39,10 @@
#include "cc/trees/single_thread_proxy.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/gpu/raster_context_provider.h"
-#include "components/viz/common/quads/shared_bitmap.h"
+#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/resources/bitmap_allocation.h"
#include "components/viz/common/resources/returned_resource.h"
+#include "components/viz/common/resources/shared_bitmap.h"
#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"
@@ -135,11 +136,11 @@ struct CommonResourceObjects {
mailbox_name2_, GL_LINEAR, arbitrary_target2, sync_token2_);
gfx::Size size(128, 128);
shared_bitmap_id_ = viz::SharedBitmap::GenerateId();
- release_callback3_ =
+ sw_release_callback_ =
base::Bind(&MockReleaseCallback::Release2,
base::Unretained(&mock_callback_), shared_bitmap_id_);
- resource3_ = viz::TransferableResource::MakeSoftware(shared_bitmap_id_,
- size, viz::RGBA_8888);
+ sw_resource_ = viz::TransferableResource::MakeSoftware(
+ shared_bitmap_id_, size, viz::RGBA_8888);
}
using RepeatingReleaseCallback =
@@ -151,13 +152,13 @@ struct CommonResourceObjects {
MockReleaseCallback mock_callback_;
RepeatingReleaseCallback release_callback1_;
RepeatingReleaseCallback release_callback2_;
- RepeatingReleaseCallback release_callback3_;
+ RepeatingReleaseCallback sw_release_callback_;
gpu::SyncToken sync_token1_;
gpu::SyncToken sync_token2_;
viz::SharedBitmapId shared_bitmap_id_;
viz::TransferableResource resource1_;
viz::TransferableResource resource2_;
- viz::TransferableResource resource3_;
+ viz::TransferableResource sw_resource_;
};
class TextureLayerTest : public testing::Test {
@@ -216,6 +217,93 @@ TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendBackgroundColor(true));
}
+class RunOnCommitLayerTreeHostClient : public FakeLayerTreeHostClient {
+ public:
+ void set_run_on_commit_and_draw(base::OnceClosure c) {
+ run_on_commit_and_draw_ = std::move(c);
+ }
+
+ void DidCommitAndDrawFrame() override {
+ if (run_on_commit_and_draw_)
+ std::move(run_on_commit_and_draw_).Run();
+ }
+
+ private:
+ base::OnceClosure run_on_commit_and_draw_;
+};
+
+// If the compositor is destroyed while TextureLayer has a resource in it, the
+// resource should be returned to the client. https://crbug.com/857262
+TEST_F(TextureLayerTest, ShutdownWithResource) {
+ for (int i = 0; i < 2; ++i) {
+ bool gpu = i == 0;
+ SCOPED_TRACE(gpu);
+ // Make our own LayerTreeHost for this test so we can control the lifetime.
+ StubLayerTreeHostSingleThreadClient single_thread_client;
+ RunOnCommitLayerTreeHostClient client;
+ LayerTreeHost::InitParams params;
+ params.client = &client;
+ params.task_graph_runner = &task_graph_runner_;
+ params.mutator_host = animation_host_.get();
+ LayerTreeSettings settings;
+ params.settings = &settings;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ auto host =
+ LayerTreeHost::CreateSingleThreaded(&single_thread_client, &params);
+
+ client.SetLayerTreeHost(host.get());
+ client.SetUseSoftwareCompositing(!gpu);
+
+ scoped_refptr<TextureLayer> layer = TextureLayer::CreateForMailbox(nullptr);
+ layer->SetIsDrawable(true);
+ layer->SetBounds(gfx::Size(10, 10));
+ if (gpu) {
+ layer->SetTransferableResource(
+ test_data_.resource1_,
+ viz::SingleReleaseCallback::Create(test_data_.release_callback1_));
+ } else {
+ layer->SetTransferableResource(
+ test_data_.sw_resource_,
+ viz::SingleReleaseCallback::Create(test_data_.sw_release_callback_));
+ }
+
+ host->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f,
+ viz::LocalSurfaceId());
+ host->SetVisible(true);
+ host->SetRootLayer(layer);
+
+ // Commit and activate the TransferableResource in the TextureLayer.
+ {
+ base::RunLoop loop;
+ client.set_run_on_commit_and_draw(loop.QuitClosure());
+ loop.Run();
+ }
+
+ // Destroy the LayerTreeHost and the compositor-thread LayerImpl trees
+ // while the resource is still in the layer. The resource should be released
+ // back to the TextureLayer's client, but is post-tasked back so...
+ host = nullptr;
+
+ // We have to wait for the posted ReleaseCallback to run.
+ // Our LayerTreeHostClient makes a FakeLayerTreeFrameSink which returns all
+ // resources when its detached, so the resources will not be in use in the
+ // display compositor, and will be returned as not lost.
+ if (gpu) {
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release(test_data_.mailbox_name1_, _, false))
+ .Times(1);
+ } else {
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release2(test_data_.shared_bitmap_id_, _, false))
+ .Times(1);
+ }
+ {
+ base::RunLoop loop;
+ loop.RunUntilIdle();
+ }
+ }
+}
+
class TestMailboxHolder : public TextureLayer::TransferableResourceHolder {
public:
using TextureLayer::TransferableResourceHolder::Create;
@@ -273,8 +361,8 @@ TEST_F(TextureLayerWithResourceTest, ReplaceMailboxOnMainThreadBeforeCommit) {
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_layer->SetTransferableResource(
- test_data_.resource3_,
- viz::SingleReleaseCallback::Create(test_data_.release_callback3_));
+ test_data_.sw_resource_,
+ viz::SingleReleaseCallback::Create(test_data_.sw_release_callback_));
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -759,7 +847,13 @@ class TextureLayerImplWithResourceTest : public TextureLayerTest {
layer_tree_host_ = MockLayerTreeHost::Create(
&fake_client_, &task_graph_runner_, animation_host_.get());
host_impl_.SetVisible(true);
- EXPECT_TRUE(host_impl_.InitializeRenderer(layer_tree_frame_sink_.get()));
+ EXPECT_TRUE(host_impl_.InitializeFrameSink(layer_tree_frame_sink_.get()));
+ }
+
+ std::unique_ptr<TextureLayerImpl> CreateTextureLayer() {
+ auto layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1);
+ layer->set_visible_layer_rect(gfx::Rect(100, 100));
+ return layer;
}
bool WillDraw(TextureLayerImpl* layer, DrawMode mode) {
@@ -785,8 +879,7 @@ TEST_F(TextureLayerImplWithResourceTest, TestWillDraw) {
.Times(AnyNumber());
// Hardware mode.
{
- std::unique_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1);
+ std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(
test_data_.resource1_,
viz::SingleReleaseCallback::Create(test_data_.release_callback1_));
@@ -802,8 +895,7 @@ TEST_F(TextureLayerImplWithResourceTest, TestWillDraw) {
// Software mode.
{
- std::unique_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1);
+ std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(
test_data_.resource1_,
viz::SingleReleaseCallback::Create(test_data_.release_callback1_));
@@ -811,26 +903,23 @@ TEST_F(TextureLayerImplWithResourceTest, TestWillDraw) {
}
{
- std::unique_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1);
+ std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(viz::TransferableResource(), nullptr);
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
{
// Software resource.
- std::unique_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1);
+ std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(
- test_data_.resource3_,
- viz::SingleReleaseCallback::Create(test_data_.release_callback3_));
+ test_data_.sw_resource_,
+ viz::SingleReleaseCallback::Create(test_data_.sw_release_callback_));
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
// Resourceless software mode.
{
- std::unique_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1);
+ std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(
test_data_.resource1_,
viz::SingleReleaseCallback::Create(test_data_.release_callback1_));
@@ -902,8 +991,7 @@ TEST_F(TextureLayerImplWithResourceTest, TestImplLayerCallbacks) {
TEST_F(TextureLayerImplWithResourceTest,
TestDestructorCallbackOnCreatedResource) {
- std::unique_ptr<TextureLayerImpl> impl_layer;
- impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1);
+ std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
ASSERT_TRUE(impl_layer);
EXPECT_CALL(test_data_.mock_callback_,
@@ -1523,6 +1611,86 @@ class SoftwareTextureLayerSwitchTreesTest : public SoftwareTextureLayerTest {
SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerSwitchTreesTest);
+// Verify that duplicate SharedBitmapIds aren't registered if resources are
+// purged due to memory pressure.
+class SoftwareTextureLayerPurgeMemoryTest : public SoftwareTextureLayerTest {
+ protected:
+ void BeginTest() override {
+ PostSetNeedsCommitToMainThread();
+
+ const gfx::Size size(1, 1);
+ const viz::ResourceFormat format = viz::RGBA_8888;
+
+ id_ = viz::SharedBitmap::GenerateId();
+ bitmap_ = base::MakeRefCounted<CrossThreadSharedBitmap>(
+ id_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size,
+ format);
+ }
+
+ void DidCommitAndDrawFrame() override {
+ step_ = layer_tree_host()->SourceFrameNumber();
+ switch (step_) {
+ case 1:
+ // The test starts by inserting the TextureLayer to the tree.
+ root_->AddChild(texture_layer_);
+ // And registers a SharedBitmapId, which should be given to the
+ // LayerTreeFrameSink.
+ registration_ = texture_layer_->RegisterSharedBitmapId(id_, bitmap_);
+ // Give the TextureLayer a resource so it contributes to the frame. It
+ // doesn't need to register the SharedBitmapId otherwise.
+ texture_layer_->SetTransferableResource(
+ viz::TransferableResource::MakeSoftware(id_, gfx::Size(1, 1),
+ viz::RGBA_8888),
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce([](const gpu::SyncToken&, bool) {})));
+ break;
+ case 2:
+ // Draw again after OnPurgeMemory() was called on the impl thread so we
+ // can verify that duplicate SharedBitmapIds aren't registered by
+ // TextureLayerImpl.
+ texture_layer_->SetNeedsDisplay();
+ break;
+ case 3:
+ // Release the TransferableResource before shutdown.
+ texture_layer_->ClearClient();
+ break;
+ case 4:
+ EndTest();
+ }
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ // TextureLayerImpl will have registered the SharedBitmapId at this point.
+ // Call OnPurgeMemory() to ensure that the same SharedBitmapId doesn't get
+ // registered again on the next draw.
+ if (step_ == 1)
+ static_cast<base::MemoryCoordinatorClient*>(host_impl)->OnPurgeMemory();
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ if (step_ == 0) {
+ // Before commit 1, the |texture_layer_| has no SharedBitmapId yet.
+ EXPECT_THAT(frame_sink_->owned_bitmaps(), testing::IsEmpty());
+ verified_frames_++;
+ } else {
+ // After commit 1, we added a SharedBitmapId to |texture_layer_|.
+ EXPECT_THAT(frame_sink_->owned_bitmaps(), testing::ElementsAre(id_));
+ verified_frames_++;
+ }
+ }
+
+ void AfterTest() override { EXPECT_EQ(4, verified_frames_); }
+
+ int step_ = 0;
+ int verified_frames_ = 0;
+ viz::SharedBitmapId id_;
+ SharedBitmapIdRegistration registration_;
+ scoped_refptr<CrossThreadSharedBitmap> bitmap_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerPurgeMemoryTest);
+
class SoftwareTextureLayerMultipleRegisterTest
: public SoftwareTextureLayerTest {
protected:
@@ -1747,8 +1915,10 @@ class SoftwareTextureLayerLoseFrameSinkTest : public SoftwareTextureLayerTest {
texture_layer_->SetTransferableResource(
viz::TransferableResource::MakeSoftware(id_, gfx::Size(1, 1),
viz::RGBA_8888),
- viz::SingleReleaseCallback::Create(
- base::BindOnce([](const gpu::SyncToken&, bool) {})));
+ viz::SingleReleaseCallback::Create(base::BindOnce(
+ &SoftwareTextureLayerLoseFrameSinkTest::ReleaseCallback,
+ base::Unretained(this))));
+ EXPECT_FALSE(released_);
break;
case 2:
// The frame sink is lost. The host will make a new one and submit
@@ -1758,24 +1928,15 @@ class SoftwareTextureLayerLoseFrameSinkTest : public SoftwareTextureLayerTest {
layer_tree_host()->ReleaseLayerTreeFrameSink().get();
layer_tree_host()->SetVisible(true);
texture_layer_->SetNeedsDisplay();
-
- // TODO(crbug.com/826886): We shouldn't need SetTransferableResource(),
- // but right now the TextureLayerImpl will drop the software resource
- // when the frame sink is lost. It needs to be able to handle this for
- // VizDisplayCompositor.
- texture_layer_->ClearClient();
- texture_layer_->SetTransferableResource(
- viz::TransferableResource::MakeSoftware(id_, gfx::Size(1, 1),
- viz::RGBA_8888),
- viz::SingleReleaseCallback::Create(
- base::BindOnce([](const gpu::SyncToken&, bool) {})));
+ EXPECT_FALSE(released_);
break;
case 3:
- // Release the TransferableResource before shutdown.
+ // Even though the frame sink was lost, the software resource given to
+ // the TextureLayer was not lost/returned.
+ EXPECT_FALSE(released_);
+ // Release the TransferableResource before shutdown, the test ends when
+ // it is released.
texture_layer_->ClearClient();
- break;
- case 4:
- EndTest();
}
}
@@ -1804,10 +1965,20 @@ class SoftwareTextureLayerLoseFrameSinkTest : public SoftwareTextureLayerTest {
}
}
+ void ReleaseCallback(const gpu::SyncToken& token, bool lost) {
+ // The software resource is not released when the LayerTreeFrameSink is lost
+ // since software resources are not destroyed by the GPU process dying. It
+ // is released only after we call TextureLayer::ClearClient().
+ EXPECT_EQ(layer_tree_host()->SourceFrameNumber(), 4);
+ released_ = true;
+ EndTest();
+ }
+
void AfterTest() override { EXPECT_EQ(3, verified_frames_); }
int step_ = 0;
int verified_frames_ = 0;
+ bool released_ = false;
viz::SharedBitmapId id_;
SharedBitmapIdRegistration registration_;
scoped_refptr<CrossThreadSharedBitmap> bitmap_;
diff --git a/chromium/cc/layers/ui_resource_layer_impl.cc b/chromium/cc/layers/ui_resource_layer_impl.cc
index 9821c27ad62..e34f189493d 100644
--- a/chromium/cc/layers/ui_resource_layer_impl.cc
+++ b/chromium/cc/layers/ui_resource_layer_impl.cc
@@ -86,7 +86,7 @@ void UIResourceLayerImpl::SetVertexOpacity(const float vertex_opacity[4]) {
bool UIResourceLayerImpl::WillDraw(
DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) {
+ viz::ClientResourceProvider* resource_provider) {
if (!ui_resource_id_ || draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
return false;
return LayerImpl::WillDraw(draw_mode, resource_provider);
diff --git a/chromium/cc/layers/ui_resource_layer_impl.h b/chromium/cc/layers/ui_resource_layer_impl.h
index ed37db2cfd1..bd94720a0e2 100644
--- a/chromium/cc/layers/ui_resource_layer_impl.h
+++ b/chromium/cc/layers/ui_resource_layer_impl.h
@@ -19,8 +19,11 @@ namespace base {
class DictionaryValue;
}
+namespace viz {
+class ClientResourceProvider;
+}
+
namespace cc {
-class LayerTreeResourceProvider;
class CC_EXPORT UIResourceLayerImpl : public LayerImpl {
public:
@@ -45,7 +48,7 @@ class CC_EXPORT UIResourceLayerImpl : public LayerImpl {
void PushPropertiesTo(LayerImpl* layer) override;
bool WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) override;
+ viz::ClientResourceProvider* resource_provider) override;
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
diff --git a/chromium/cc/layers/ui_resource_layer_impl_unittest.cc b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc
index b248d3da78e..db2f6d25863 100644
--- a/chromium/cc/layers/ui_resource_layer_impl_unittest.cc
+++ b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc
@@ -71,7 +71,7 @@ TEST(UIResourceLayerImplTest, VerifyDrawQuads) {
FakeUIResourceLayerTreeHostImpl host_impl(&task_runner_provider,
&task_graph_runner);
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
// Make sure we're appending quads when there are valid values.
gfx::Size bitmap_size(100, 100);
@@ -82,6 +82,7 @@ TEST(UIResourceLayerImplTest, VerifyDrawQuads) {
std::unique_ptr<UIResourceLayerImpl> layer =
GenerateUIResourceLayer(&host_impl, bitmap_size, layer_size, opaque, uid);
QuadSizeTest(&host_impl, std::move(layer), expected_quad_size);
+ host_impl.DeleteUIResource(uid);
// Make sure we're not appending quads when there are invalid values.
expected_quad_size = 0;
@@ -92,6 +93,7 @@ TEST(UIResourceLayerImplTest, VerifyDrawQuads) {
opaque,
uid);
QuadSizeTest(&host_impl, std::move(layer), expected_quad_size);
+ host_impl.DeleteUIResource(uid);
}
void NeedsBlendingTest(FakeUIResourceLayerTreeHostImpl* host_impl,
@@ -124,7 +126,7 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnSkBitmap) {
FakeUIResourceLayerTreeHostImpl host_impl(&task_runner_provider,
&task_graph_runner);
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
gfx::Size bitmap_size(100, 100);
gfx::Size layer_size(100, 100);
@@ -133,6 +135,7 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnSkBitmap) {
std::unique_ptr<UIResourceLayerImpl> layer =
GenerateUIResourceLayer(&host_impl, bitmap_size, layer_size, opaque, uid);
NeedsBlendingTest(&host_impl, std::move(layer), !opaque);
+ host_impl.DeleteUIResource(uid);
opaque = true;
layer = GenerateUIResourceLayer(&host_impl,
@@ -141,6 +144,7 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnSkBitmap) {
opaque,
uid);
NeedsBlendingTest(&host_impl, std::move(layer), !opaque);
+ host_impl.DeleteUIResource(uid);
}
TEST(UIResourceLayerImplTest, VerifySetOpaqueOnLayer) {
@@ -151,7 +155,7 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnLayer) {
FakeUIResourceLayerTreeHostImpl host_impl(&task_runner_provider,
&task_graph_runner);
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
gfx::Size bitmap_size(100, 100);
gfx::Size layer_size(100, 100);
@@ -162,12 +166,14 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnLayer) {
bool opaque = false;
layer->SetContentsOpaque(opaque);
NeedsBlendingTest(&host_impl, std::move(layer), !opaque);
+ host_impl.DeleteUIResource(uid);
opaque = true;
layer = GenerateUIResourceLayer(
&host_impl, bitmap_size, layer_size, skbitmap_opaque, uid);
layer->SetContentsOpaque(true);
NeedsBlendingTest(&host_impl, std::move(layer), !opaque);
+ host_impl.DeleteUIResource(uid);
}
TEST(UIResourceLayerImplTest, Occlusion) {
diff --git a/chromium/cc/layers/ui_resource_layer_unittest.cc b/chromium/cc/layers/ui_resource_layer_unittest.cc
index e4e21aabf65..17397773b5b 100644
--- a/chromium/cc/layers/ui_resource_layer_unittest.cc
+++ b/chromium/cc/layers/ui_resource_layer_unittest.cc
@@ -57,7 +57,7 @@ TEST_F(UIResourceLayerTest, SetBitmap) {
layer_tree_host()->SetRootLayer(test_layer);
Mock::VerifyAndClearExpectations(layer_tree_host());
- EXPECT_EQ(test_layer->GetLayerTreeHostForTesting(), layer_tree_host());
+ EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host());
test_layer->Update();
@@ -80,7 +80,7 @@ TEST_F(UIResourceLayerTest, SetUIResourceId) {
layer_tree_host()->SetRootLayer(test_layer);
Mock::VerifyAndClearExpectations(layer_tree_host());
- EXPECT_EQ(test_layer->GetLayerTreeHostForTesting(), layer_tree_host());
+ EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host());
test_layer->Update();
diff --git a/chromium/cc/layers/video_frame_provider.h b/chromium/cc/layers/video_frame_provider.h
index e610d4df91b..af413093231 100644
--- a/chromium/cc/layers/video_frame_provider.h
+++ b/chromium/cc/layers/video_frame_provider.h
@@ -39,12 +39,23 @@ class CC_EXPORT VideoFrameProvider {
// Callers should use these methods to indicate when it expects and no
// longer expects (respectively) to have new frames for the client. Clients
// may use this information for power conservation.
+ //
+ // Note that the client may also choose to stop driving frame updates, such
+ // as if it believes that the frames are not visible. In this case, the
+ // client should report this via IsDrivingFrameUpdates().
virtual void StartRendering() = 0;
virtual void StopRendering() = 0;
// Notifies the client that GetCurrentFrame() will return new data.
virtual void DidReceiveFrame() = 0;
+ // Should return true if and only if the client is actively driving frame
+ // updates. Note that this implies that the client has been told to
+ // StartRendering by the VideoFrameProvider. However, it's okay if the
+ // client chooses to elide these calls, for example to save power when the
+ // client knows that the frames are not visible.
+ virtual bool IsDrivingFrameUpdates() const = 0;
+
protected:
virtual ~Client() {}
};
diff --git a/chromium/cc/layers/video_frame_provider_client_impl.cc b/chromium/cc/layers/video_frame_provider_client_impl.cc
index ea4499cfebf..51eb3eec062 100644
--- a/chromium/cc/layers/video_frame_provider_client_impl.cc
+++ b/chromium/cc/layers/video_frame_provider_client_impl.cc
@@ -177,4 +177,9 @@ void VideoFrameProviderClientImpl::DidDrawFrame() {
needs_put_current_frame_ = false;
}
+bool VideoFrameProviderClientImpl::IsDrivingFrameUpdates() const {
+ // We drive frame updates any time we're rendering, even if we're off-screen.
+ return rendering_;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/video_frame_provider_client_impl.h b/chromium/cc/layers/video_frame_provider_client_impl.h
index bc2f370e674..6c11f72b0a0 100644
--- a/chromium/cc/layers/video_frame_provider_client_impl.h
+++ b/chromium/cc/layers/video_frame_provider_client_impl.h
@@ -56,6 +56,7 @@ class CC_EXPORT VideoFrameProviderClientImpl
void StartRendering() override;
void StopRendering() override;
void DidReceiveFrame() override;
+ bool IsDrivingFrameUpdates() const override;
const VideoFrameProvider* get_provider_for_testing() const {
return provider_;
diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc
index 4e2843f2ca3..d4a18b06d92 100644
--- a/chromium/cc/layers/video_layer_impl.cc
+++ b/chromium/cc/layers/video_layer_impl.cc
@@ -10,16 +10,17 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "cc/layers/video_frame_provider_client_impl.h"
-#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/occlusion.h"
#include "cc/trees/task_runner_provider.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/quads/stream_video_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "components/viz/common/resources/single_release_callback.h"
#include "media/base/video_frame.h"
+#include "media/renderers/video_resource_updater.h"
#include "ui/gfx/color_space.h"
namespace cc {
@@ -77,10 +78,13 @@ void VideoLayerImpl::DidBecomeActive() {
}
bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) {
+ viz::ClientResourceProvider* resource_provider) {
if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
return false;
+ if (!LayerImpl::WillDraw(draw_mode, resource_provider))
+ return false;
+
// Explicitly acquire and release the provider mutex so it can be held from
// WillDraw to DidDraw. Since the compositor thread is in the middle of
// drawing, the layer will not be destroyed before DidDraw is called.
@@ -98,12 +102,9 @@ bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
return false;
}
- if (!LayerImpl::WillDraw(draw_mode, resource_provider))
- return false;
-
if (!updater_) {
const LayerTreeSettings& settings = layer_tree_impl()->settings();
- updater_ = std::make_unique<VideoResourceUpdater>(
+ updater_ = std::make_unique<media::VideoResourceUpdater>(
layer_tree_impl()->context_provider(),
layer_tree_impl()->layer_tree_frame_sink(),
layer_tree_impl()->resource_provider(),
@@ -158,7 +159,7 @@ void VideoLayerImpl::AppendQuads(viz::RenderPass* render_pass,
GetSortingContextId(), visible_quad_rect);
}
-void VideoLayerImpl::DidDraw(LayerTreeResourceProvider* resource_provider) {
+void VideoLayerImpl::DidDraw(viz::ClientResourceProvider* resource_provider) {
LayerImpl::DidDraw(resource_provider);
DCHECK(frame_.get());
diff --git a/chromium/cc/layers/video_layer_impl.h b/chromium/cc/layers/video_layer_impl.h
index 30d10551b60..4b3646b0e16 100644
--- a/chromium/cc/layers/video_layer_impl.h
+++ b/chromium/cc/layers/video_layer_impl.h
@@ -10,12 +10,12 @@
#include "base/macros.h"
#include "cc/cc_export.h"
#include "cc/layers/layer_impl.h"
-#include "cc/resources/video_resource_updater.h"
#include "components/viz/common/resources/release_callback.h"
#include "media/base/video_rotation.h"
namespace media {
class VideoFrame;
+class VideoResourceUpdater;
}
namespace cc {
@@ -36,10 +36,10 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl {
// LayerImpl implementation.
std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
bool WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* resource_provider) override;
+ viz::ClientResourceProvider* resource_provider) override;
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
- void DidDraw(LayerTreeResourceProvider* resource_provider) override;
+ void DidDraw(viz::ClientResourceProvider* resource_provider) override;
SimpleEnclosedRegion VisibleOpaqueRegion() const override;
void DidBecomeActive() override;
void ReleaseResources() override;
@@ -62,7 +62,7 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl {
media::VideoRotation video_rotation_;
- std::unique_ptr<VideoResourceUpdater> updater_;
+ std::unique_ptr<media::VideoResourceUpdater> updater_;
DISALLOW_COPY_AND_ASSIGN(VideoLayerImpl);
};
diff --git a/chromium/cc/layers/video_layer_impl_unittest.cc b/chromium/cc/layers/video_layer_impl_unittest.cc
index fc676280302..56d917040a3 100644
--- a/chromium/cc/layers/video_layer_impl_unittest.cc
+++ b/chromium/cc/layers/video_layer_impl_unittest.cc
@@ -50,6 +50,7 @@ TEST(VideoLayerImplTest, Occlusion) {
impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0);
video_layer_impl->SetBounds(layer_size);
video_layer_impl->SetDrawsContent(true);
+ video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size));
impl.CalcDrawProps(viewport_size);
@@ -313,6 +314,7 @@ TEST(VideoLayerImplTest, SoftwareVideoFrameGeneratesYUVQuad) {
impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0);
video_layer_impl->SetBounds(layer_size);
video_layer_impl->SetDrawsContent(true);
+ video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size));
impl.host_impl()->active_tree()->BuildLayerListAndPropertyTreesForTesting();
gfx::Rect occluded;
@@ -350,6 +352,7 @@ TEST(VideoLayerImplTest, HibitSoftwareVideoFrameGeneratesYUVQuad) {
impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0);
video_layer_impl->SetBounds(layer_size);
video_layer_impl->SetDrawsContent(true);
+ video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size));
impl.host_impl()->active_tree()->BuildLayerListAndPropertyTreesForTesting();
gfx::Rect occluded;
@@ -393,6 +396,7 @@ TEST(VideoLayerImplTest, NativeYUVFrameGeneratesYUVQuad) {
impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0);
video_layer_impl->SetBounds(layer_size);
video_layer_impl->SetDrawsContent(true);
+ video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size));
impl.host_impl()->active_tree()->BuildLayerListAndPropertyTreesForTesting();
gfx::Rect occluded;
@@ -436,6 +440,7 @@ TEST(VideoLayerImplTest, NativeARGBFrameGeneratesTextureQuad) {
impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0);
video_layer_impl->SetBounds(layer_size);
video_layer_impl->SetDrawsContent(true);
+ video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size));
impl.host_impl()->active_tree()->BuildLayerListAndPropertyTreesForTesting();
gfx::Rect occluded;
diff --git a/chromium/cc/layers/viewport.cc b/chromium/cc/layers/viewport.cc
index fe4371883bb..b99cee33e8a 100644
--- a/chromium/cc/layers/viewport.cc
+++ b/chromium/cc/layers/viewport.cc
@@ -30,7 +30,8 @@ void Viewport::Pan(const gfx::Vector2dF& delta) {
gfx::Vector2dF pending_delta = delta;
float page_scale = host_impl_->active_tree()->current_page_scale_factor();
pending_delta.Scale(1 / page_scale);
- InnerScrollLayer()->ScrollBy(pending_delta);
+ scroll_tree().ScrollBy(InnerScrollNode(), pending_delta,
+ host_impl_->active_tree());
}
Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta,
@@ -38,7 +39,7 @@ Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta,
bool is_direct_manipulation,
bool affect_browser_controls,
bool scroll_outer_viewport) {
- if (!OuterScrollLayer())
+ if (!OuterScrollNode())
return ScrollResult();
gfx::Vector2dF content_delta = delta;
@@ -48,22 +49,17 @@ Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta,
gfx::Vector2dF pending_content_delta = content_delta;
- ScrollTree& scroll_tree =
- host_impl_->active_tree()->property_trees()->scroll_tree;
- ScrollNode* inner_node =
- scroll_tree.Node(InnerScrollLayer()->scroll_tree_index());
+ ScrollNode* inner_node = InnerScrollNode();
pending_content_delta -= host_impl_->ScrollSingleNode(
inner_node, pending_content_delta, viewport_point, is_direct_manipulation,
- &scroll_tree);
+ &scroll_tree());
ScrollResult result;
if (scroll_outer_viewport) {
- ScrollNode* outer_node =
- scroll_tree.Node(OuterScrollLayer()->scroll_tree_index());
pending_content_delta -= host_impl_->ScrollSingleNode(
- outer_node, pending_content_delta, viewport_point,
- is_direct_manipulation, &scroll_tree);
+ OuterScrollNode(), pending_content_delta, viewport_point,
+ is_direct_manipulation, &scroll_tree());
}
result.consumed_delta = delta - AdjustOverscroll(pending_content_delta);
@@ -73,30 +69,28 @@ Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta,
}
bool Viewport::CanScroll(const ScrollState& scroll_state) const {
- if (!OuterScrollLayer())
+ auto* outer_node = OuterScrollNode();
+
+ if (!outer_node)
return false;
bool result = false;
- ScrollTree& scroll_tree =
- host_impl_->active_tree()->property_trees()->scroll_tree;
- ScrollNode* inner_node =
- scroll_tree.Node(InnerScrollLayer()->scroll_tree_index());
- if (inner_node)
+ if (auto* inner_node = InnerScrollNode())
result |= host_impl_->CanConsumeDelta(*inner_node, scroll_state);
- ScrollNode* outer_node =
- scroll_tree.Node(OuterScrollLayer()->scroll_tree_index());
- if (outer_node)
- result |= host_impl_->CanConsumeDelta(*outer_node, scroll_state);
+
+ result |= host_impl_->CanConsumeDelta(*outer_node, scroll_state);
return result;
}
void Viewport::ScrollByInnerFirst(const gfx::Vector2dF& delta) {
- LayerImpl* scroll_layer = InnerScrollLayer();
+ gfx::Vector2dF unused_delta = scroll_tree().ScrollBy(
+ InnerScrollNode(), delta, host_impl_->active_tree());
- gfx::Vector2dF unused_delta = scroll_layer->ScrollBy(delta);
- if (!unused_delta.IsZero() && OuterScrollLayer())
- OuterScrollLayer()->ScrollBy(unused_delta);
+ auto* outer_node = OuterScrollNode();
+ if (!unused_delta.IsZero() && outer_node) {
+ scroll_tree().ScrollBy(outer_node, unused_delta, host_impl_->active_tree());
+ }
}
bool Viewport::ShouldAnimateViewport(const gfx::Vector2dF& viewport_delta,
@@ -110,26 +104,21 @@ bool Viewport::ShouldAnimateViewport(const gfx::Vector2dF& viewport_delta,
gfx::Vector2dF Viewport::ScrollAnimated(const gfx::Vector2dF& delta,
base::TimeDelta delayed_by) {
- if (!OuterScrollLayer())
+ auto* outer_node = OuterScrollNode();
+ if (!outer_node)
return gfx::Vector2dF(0, 0);
- ScrollTree& scroll_tree =
- host_impl_->active_tree()->property_trees()->scroll_tree;
-
float scale_factor = host_impl_->active_tree()->current_page_scale_factor();
gfx::Vector2dF scaled_delta = delta;
scaled_delta.Scale(1.f / scale_factor);
- ScrollNode* inner_node =
- scroll_tree.Node(InnerScrollLayer()->scroll_tree_index());
+ ScrollNode* inner_node = InnerScrollNode();
gfx::Vector2dF inner_delta =
host_impl_->ComputeScrollDelta(*inner_node, delta);
gfx::Vector2dF pending_delta = scaled_delta - inner_delta;
pending_delta.Scale(scale_factor);
- ScrollNode* outer_node =
- scroll_tree.Node(OuterScrollLayer()->scroll_tree_index());
gfx::Vector2dF outer_delta =
host_impl_->ComputeScrollDelta(*outer_node, pending_delta);
@@ -142,11 +131,11 @@ gfx::Vector2dF Viewport::ScrollAnimated(const gfx::Vector2dF& delta,
// viewports.
bool will_animate = false;
if (ShouldAnimateViewport(inner_delta, outer_delta)) {
- scroll_tree.ScrollBy(outer_node, outer_delta, host_impl_->active_tree());
+ scroll_tree().ScrollBy(outer_node, outer_delta, host_impl_->active_tree());
will_animate =
host_impl_->ScrollAnimationCreate(inner_node, inner_delta, delayed_by);
} else {
- scroll_tree.ScrollBy(inner_node, inner_delta, host_impl_->active_tree());
+ scroll_tree().ScrollBy(inner_node, inner_delta, host_impl_->active_tree());
will_animate =
host_impl_->ScrollAnimationCreate(outer_node, outer_delta, delayed_by);
}
@@ -161,8 +150,7 @@ gfx::Vector2dF Viewport::ScrollAnimated(const gfx::Vector2dF& delta,
}
void Viewport::SnapPinchAnchorIfWithinMargin(const gfx::Point& anchor) {
- gfx::SizeF viewport_size = gfx::SizeF(
- host_impl_->active_tree()->InnerViewportContainerLayer()->bounds());
+ gfx::SizeF viewport_size = gfx::SizeF(InnerScrollNode()->container_bounds);
if (anchor.x() < kPinchZoomSnapMarginDips)
pinch_anchor_adjustment_.set_x(-anchor.x());
@@ -206,19 +194,16 @@ void Viewport::PinchUpdate(float magnify_delta, const gfx::Point& anchor) {
// If clamping the inner viewport scroll offset causes a change, it should
// be accounted for from the intended move.
- move -= InnerScrollLayer()->ClampScrollToMaxScrollOffset();
+ move -= scroll_tree().ClampScrollToMaxScrollOffset(InnerScrollNode(),
+ host_impl_->active_tree());
Pan(move);
}
void Viewport::PinchEnd(const gfx::Point& anchor, bool snap_to_min) {
- LayerTreeImpl* active_tree = host_impl_->active_tree();
- // TODO(mcnee): Remove the InnerViewportScrollLayer() check (and add a
- // DCHECK instead), after we no longer send GesturePinch events to
- // OOPIF renderers. https://crbug.com/787924
- // Snap-to-min only makes sense for mainframes, so we use the lack of an
- // InnerViewportScrollLayer() to detect if this is an OOPIF.
- if (snap_to_min && active_tree->InnerViewportScrollLayer()) {
+ if (snap_to_min) {
+ LayerTreeImpl* active_tree = host_impl_->active_tree();
+ DCHECK(active_tree->InnerViewportScrollNode());
const float kMaxZoomForSnapToMin = 1.05f;
const base::TimeDelta kSnapToMinZoomAnimationDuration =
base::TimeDelta::FromMilliseconds(200);
@@ -226,7 +211,8 @@ void Viewport::PinchEnd(const gfx::Point& anchor, bool snap_to_min) {
float min_scale = active_tree->min_page_scale_factor();
// If the page is close to minimum scale at pinch end, snap to minimum.
- if (page_scale < min_scale * kMaxZoomForSnapToMin) {
+ if (page_scale < min_scale * kMaxZoomForSnapToMin &&
+ page_scale != min_scale) {
gfx::PointF adjusted_anchor =
gfx::PointF(anchor + pinch_anchor_adjustment_);
adjusted_anchor =
@@ -243,7 +229,7 @@ void Viewport::PinchEnd(const gfx::Point& anchor, bool snap_to_min) {
}
LayerImpl* Viewport::MainScrollLayer() const {
- return OuterScrollLayer();
+ return host_impl_->OuterViewportScrollLayer();
}
gfx::Vector2dF Viewport::ScrollBrowserControls(const gfx::Vector2dF& delta) {
@@ -282,10 +268,10 @@ gfx::Vector2dF Viewport::AdjustOverscroll(const gfx::Vector2dF& delta) const {
gfx::ScrollOffset Viewport::MaxTotalScrollOffset() const {
gfx::ScrollOffset offset;
- offset += InnerScrollLayer()->MaxScrollOffset();
+ offset += scroll_tree().MaxScrollOffset(InnerScrollNode()->id);
- if (OuterScrollLayer())
- offset += OuterScrollLayer()->MaxScrollOffset();
+ if (auto* outer_node = OuterScrollNode())
+ offset += scroll_tree().MaxScrollOffset(outer_node->id);
return offset;
}
@@ -293,20 +279,24 @@ gfx::ScrollOffset Viewport::MaxTotalScrollOffset() const {
gfx::ScrollOffset Viewport::TotalScrollOffset() const {
gfx::ScrollOffset offset;
- offset += InnerScrollLayer()->CurrentScrollOffset();
+ offset += scroll_tree().current_scroll_offset(InnerScrollNode()->element_id);
- if (OuterScrollLayer())
- offset += OuterScrollLayer()->CurrentScrollOffset();
+ if (auto* outer_node = OuterScrollNode())
+ offset += scroll_tree().current_scroll_offset(outer_node->element_id);
return offset;
}
-LayerImpl* Viewport::InnerScrollLayer() const {
- return host_impl_->InnerViewportScrollLayer();
+ScrollNode* Viewport::InnerScrollNode() const {
+ return host_impl_->InnerViewportScrollNode();
}
-LayerImpl* Viewport::OuterScrollLayer() const {
- return host_impl_->OuterViewportScrollLayer();
+ScrollNode* Viewport::OuterScrollNode() const {
+ return host_impl_->OuterViewportScrollNode();
+}
+
+ScrollTree& Viewport::scroll_tree() const {
+ return host_impl_->active_tree()->property_trees()->scroll_tree;
}
} // namespace cc
diff --git a/chromium/cc/layers/viewport.h b/chromium/cc/layers/viewport.h
index 0d8f3afaddf..275e826919f 100644
--- a/chromium/cc/layers/viewport.h
+++ b/chromium/cc/layers/viewport.h
@@ -15,6 +15,7 @@
namespace cc {
class LayerTreeHostImpl;
+struct ScrollNode;
// Encapsulates gesture handling logic on the viewport layers. The "viewport"
// is made up of two scrolling layers, the inner viewport (visual) and the
@@ -87,8 +88,9 @@ class CC_EXPORT Viewport {
gfx::ScrollOffset MaxTotalScrollOffset() const;
- LayerImpl* InnerScrollLayer() const;
- LayerImpl* OuterScrollLayer() const;
+ ScrollNode* InnerScrollNode() const;
+ ScrollNode* OuterScrollNode() const;
+ ScrollTree& scroll_tree() const;
void SnapPinchAnchorIfWithinMargin(const gfx::Point& anchor);
diff --git a/chromium/cc/mojo_embedder/BUILD.gn b/chromium/cc/mojo_embedder/BUILD.gn
new file mode 100644
index 00000000000..3abdc4ca5c9
--- /dev/null
+++ b/chromium/cc/mojo_embedder/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright 2017 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.
+
+import("//cc/cc.gni")
+
+cc_component("mojo_embedder") {
+ output_name = "cc_mojo_embedder"
+ sources = [
+ "async_layer_tree_frame_sink.cc",
+ "async_layer_tree_frame_sink.h",
+ ]
+
+ defines = [ "CC_MOJO_EMBEDDER_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//cc",
+ "//components/viz/client",
+ "//components/viz/common",
+ "//mojo/public/cpp/bindings",
+ "//services/viz/public/interfaces",
+ ]
+}
diff --git a/chromium/cc/mojo_embedder/DEPS b/chromium/cc/mojo_embedder/DEPS
new file mode 100644
index 00000000000..d5c8e6fc631
--- /dev/null
+++ b/chromium/cc/mojo_embedder/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+mojo/public/cpp/bindings",
+ "+services/viz/public/interfaces/compositing",
+]
diff --git a/chromium/cc/mojo_embedder/README.md b/chromium/cc/mojo_embedder/README.md
new file mode 100644
index 00000000000..2585c5863b2
--- /dev/null
+++ b/chromium/cc/mojo_embedder/README.md
@@ -0,0 +1,4 @@
+# cc/mojo_embedder/
+
+This directory contains mojo bindings for connecting cc to viz via mojo.
+
diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
new file mode 100644
index 00000000000..8e155e4e4de
--- /dev/null
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -0,0 +1,256 @@
+// Copyright 2017 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/mojo_embedder/async_layer_tree_frame_sink.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/trees/layer_tree_frame_sink_client.h"
+#include "components/viz/client/hit_test_data_provider.h"
+#include "components/viz/client/local_surface_id_provider.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/hit_test/hit_test_region_list.h"
+#include "components/viz/common/quads/compositor_frame.h"
+
+namespace cc {
+namespace mojo_embedder {
+
+AsyncLayerTreeFrameSink::InitParams::InitParams() = default;
+AsyncLayerTreeFrameSink::InitParams::~InitParams() = default;
+
+AsyncLayerTreeFrameSink::UnboundMessagePipes::UnboundMessagePipes() = default;
+AsyncLayerTreeFrameSink::UnboundMessagePipes::~UnboundMessagePipes() = default;
+
+bool AsyncLayerTreeFrameSink::UnboundMessagePipes::HasUnbound() const {
+ return client_request.is_pending() &&
+ (compositor_frame_sink_info.is_valid() ^
+ compositor_frame_sink_associated_info.is_valid());
+}
+
+AsyncLayerTreeFrameSink::UnboundMessagePipes::UnboundMessagePipes(
+ UnboundMessagePipes&& other) = default;
+
+AsyncLayerTreeFrameSink::AsyncLayerTreeFrameSink(
+ scoped_refptr<viz::ContextProvider> context_provider,
+ scoped_refptr<viz::RasterContextProvider> worker_context_provider,
+ InitParams* params)
+ : LayerTreeFrameSink(std::move(context_provider),
+ std::move(worker_context_provider),
+ std::move(params->compositor_task_runner),
+ params->gpu_memory_buffer_manager),
+ hit_test_data_provider_(std::move(params->hit_test_data_provider)),
+ local_surface_id_provider_(std::move(params->local_surface_id_provider)),
+ synthetic_begin_frame_source_(
+ std::move(params->synthetic_begin_frame_source)),
+ pipes_(std::move(params->pipes)),
+ client_binding_(this),
+ enable_surface_synchronization_(params->enable_surface_synchronization),
+ wants_animate_only_begin_frames_(params->wants_animate_only_begin_frames),
+ weak_factory_(this) {
+ DETACH_FROM_THREAD(thread_checker_);
+}
+
+AsyncLayerTreeFrameSink::~AsyncLayerTreeFrameSink() {}
+
+bool AsyncLayerTreeFrameSink::BindToClient(LayerTreeFrameSinkClient* client) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (!LayerTreeFrameSink::BindToClient(client))
+ return false;
+
+ DCHECK(pipes_.HasUnbound());
+ if (pipes_.compositor_frame_sink_info.is_valid()) {
+ compositor_frame_sink_.Bind(std::move(pipes_.compositor_frame_sink_info));
+ compositor_frame_sink_.set_connection_error_with_reason_handler(
+ base::BindOnce(&AsyncLayerTreeFrameSink::OnMojoConnectionError,
+ weak_factory_.GetWeakPtr()));
+ compositor_frame_sink_ptr_ = compositor_frame_sink_.get();
+ } else if (pipes_.compositor_frame_sink_associated_info.is_valid()) {
+ compositor_frame_sink_associated_.Bind(
+ std::move(pipes_.compositor_frame_sink_associated_info));
+ compositor_frame_sink_associated_.set_connection_error_with_reason_handler(
+ base::BindOnce(&AsyncLayerTreeFrameSink::OnMojoConnectionError,
+ weak_factory_.GetWeakPtr()));
+ compositor_frame_sink_ptr_ = compositor_frame_sink_associated_.get();
+ }
+ client_binding_.Bind(std::move(pipes_.client_request),
+ compositor_task_runner_);
+
+ if (synthetic_begin_frame_source_) {
+ client->SetBeginFrameSource(synthetic_begin_frame_source_.get());
+ } else {
+ begin_frame_source_ = std::make_unique<viz::ExternalBeginFrameSource>(this);
+ begin_frame_source_->OnSetBeginFrameSourcePaused(begin_frames_paused_);
+ client->SetBeginFrameSource(begin_frame_source_.get());
+ }
+
+ if (wants_animate_only_begin_frames_)
+ compositor_frame_sink_->SetWantsAnimateOnlyBeginFrames();
+
+ return true;
+}
+
+void AsyncLayerTreeFrameSink::DetachFromClient() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ client_->SetBeginFrameSource(nullptr);
+ begin_frame_source_.reset();
+ synthetic_begin_frame_source_.reset();
+ client_binding_.Close();
+ compositor_frame_sink_.reset();
+ compositor_frame_sink_associated_.reset();
+ compositor_frame_sink_ptr_ = nullptr;
+ LayerTreeFrameSink::DetachFromClient();
+}
+
+void AsyncLayerTreeFrameSink::SetLocalSurfaceId(
+ const viz::LocalSurfaceId& local_surface_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(local_surface_id.is_valid());
+ DCHECK(enable_surface_synchronization_);
+ local_surface_id_ = local_surface_id;
+}
+
+void AsyncLayerTreeFrameSink::SubmitCompositorFrame(
+ viz::CompositorFrame frame) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(compositor_frame_sink_ptr_);
+ DCHECK(frame.metadata.begin_frame_ack.has_damage);
+ DCHECK_LE(viz::BeginFrameArgs::kStartingFrameNumber,
+ frame.metadata.begin_frame_ack.sequence_number);
+ TRACE_EVENT_WITH_FLOW1(
+ "viz,benchmark", "Graphics.Pipeline",
+ TRACE_ID_GLOBAL(frame.metadata.begin_frame_ack.trace_id),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
+ "SubmitCompositorFrame");
+
+ if (!enable_surface_synchronization_) {
+ local_surface_id_ =
+ local_surface_id_provider_->GetLocalSurfaceIdForFrame(frame);
+ } else {
+ if (local_surface_id_ == last_submitted_local_surface_id_) {
+ DCHECK_EQ(last_submitted_device_scale_factor_,
+ frame.device_scale_factor());
+ DCHECK_EQ(last_submitted_size_in_pixels_.height(),
+ frame.size_in_pixels().height());
+ DCHECK_EQ(last_submitted_size_in_pixels_.width(),
+ frame.size_in_pixels().width());
+ }
+ }
+
+ 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);
+ else
+ hit_test_region_list = client_->BuildHitTestData();
+
+ if (last_submitted_local_surface_id_ != local_surface_id_) {
+ last_submitted_local_surface_id_ = local_surface_id_;
+ last_submitted_device_scale_factor_ = frame.device_scale_factor();
+ last_submitted_size_in_pixels_ = frame.size_in_pixels();
+
+ TRACE_EVENT_WITH_FLOW2(
+ TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
+ "LocalSurfaceId.Submission.Flow",
+ TRACE_ID_GLOBAL(local_surface_id_.submission_trace_id()),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
+ "SubmitCompositorFrame", "surface_id", local_surface_id_.ToString());
+ }
+
+ 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);
+}
+
+void AsyncLayerTreeFrameSink::DidNotProduceFrame(
+ const viz::BeginFrameAck& ack) {
+ DCHECK(compositor_frame_sink_ptr_);
+ DCHECK(!ack.has_damage);
+ DCHECK_LE(viz::BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
+ compositor_frame_sink_ptr_->DidNotProduceFrame(ack);
+}
+
+void AsyncLayerTreeFrameSink::DidAllocateSharedBitmap(
+ mojo::ScopedSharedBufferHandle buffer,
+ const viz::SharedBitmapId& id) {
+ DCHECK(compositor_frame_sink_ptr_);
+ compositor_frame_sink_ptr_->DidAllocateSharedBitmap(std::move(buffer), id);
+}
+
+void AsyncLayerTreeFrameSink::DidDeleteSharedBitmap(
+ const viz::SharedBitmapId& id) {
+ DCHECK(compositor_frame_sink_ptr_);
+ compositor_frame_sink_ptr_->DidDeleteSharedBitmap(id);
+}
+
+void AsyncLayerTreeFrameSink::DidReceiveCompositorFrameAck(
+ const std::vector<viz::ReturnedResource>& resources) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ client_->ReclaimResources(resources);
+ client_->DidReceiveCompositorFrameAck();
+}
+
+void AsyncLayerTreeFrameSink::DidPresentCompositorFrame(
+ uint32_t presentation_token,
+ const gfx::PresentationFeedback& feedback) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ client_->DidPresentCompositorFrame(presentation_token, feedback);
+}
+
+void AsyncLayerTreeFrameSink::OnBeginFrame(const viz::BeginFrameArgs& args) {
+ if (!needs_begin_frames_) {
+ TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
+ TRACE_ID_GLOBAL(args.trace_id),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "step", "ReceiveBeginFrameDiscard");
+ // We had a race with SetNeedsBeginFrame(false) and still need to let the
+ // sink know that we didn't use this BeginFrame.
+ DidNotProduceFrame(viz::BeginFrameAck(args, false));
+ } else {
+ TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
+ TRACE_ID_GLOBAL(args.trace_id),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "step", "ReceiveBeginFrame");
+ }
+ if (begin_frame_source_)
+ begin_frame_source_->OnBeginFrame(args);
+}
+
+void AsyncLayerTreeFrameSink::OnBeginFramePausedChanged(bool paused) {
+ begin_frames_paused_ = paused;
+ if (begin_frame_source_)
+ begin_frame_source_->OnSetBeginFrameSourcePaused(paused);
+}
+
+void AsyncLayerTreeFrameSink::ReclaimResources(
+ const std::vector<viz::ReturnedResource>& resources) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ client_->ReclaimResources(resources);
+}
+
+void AsyncLayerTreeFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
+ DCHECK(compositor_frame_sink_ptr_);
+ needs_begin_frames_ = needs_begin_frames;
+ compositor_frame_sink_ptr_->SetNeedsBeginFrame(needs_begin_frames);
+}
+
+void AsyncLayerTreeFrameSink::OnMojoConnectionError(
+ uint32_t custom_reason,
+ const std::string& description) {
+ if (custom_reason)
+ DLOG(FATAL) << description;
+ if (client_)
+ client_->DidLoseLayerTreeFrameSink();
+}
+
+} // namespace mojo_embedder
+} // namespace cc
diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
new file mode 100644
index 00000000000..28bbfdf7252
--- /dev/null
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
@@ -0,0 +1,149 @@
+// Copyright 2017 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_MOJO_EMBEDDER_ASYNC_LAYER_TREE_FRAME_SINK_H_
+#define CC_MOJO_EMBEDDER_ASYNC_LAYER_TREE_FRAME_SINK_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.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/gpu/context_provider.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"
+#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
+
+namespace viz {
+class HitTestDataProvider;
+class LocalSurfaceIdProvider;
+} // namespace viz
+
+namespace cc {
+namespace mojo_embedder {
+
+// A mojo-based implementation of LayerTreeFrameSink. The typically-used
+// implementation for cc instances that do not share a process with the viz
+// display compositor.
+class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink
+ : public LayerTreeFrameSink,
+ public viz::mojom::CompositorFrameSinkClient,
+ public viz::ExternalBeginFrameSourceClient {
+ public:
+ struct CC_MOJO_EMBEDDER_EXPORT UnboundMessagePipes {
+ UnboundMessagePipes();
+ ~UnboundMessagePipes();
+ UnboundMessagePipes(UnboundMessagePipes&& other);
+
+ bool HasUnbound() const;
+
+ // Only one of |compositor_frame_sink_info| or
+ // |compositor_frame_sink_associated_info| should be set.
+ viz::mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info;
+ viz::mojom::CompositorFrameSinkAssociatedPtrInfo
+ compositor_frame_sink_associated_info;
+ viz::mojom::CompositorFrameSinkClientRequest client_request;
+ };
+
+ struct CC_MOJO_EMBEDDER_EXPORT InitParams {
+ InitParams();
+ ~InitParams();
+
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner;
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = nullptr;
+ std::unique_ptr<viz::SyntheticBeginFrameSource>
+ synthetic_begin_frame_source;
+ std::unique_ptr<viz::HitTestDataProvider> hit_test_data_provider;
+ std::unique_ptr<viz::LocalSurfaceIdProvider> local_surface_id_provider;
+ UnboundMessagePipes pipes;
+ bool enable_surface_synchronization = false;
+ bool wants_animate_only_begin_frames = false;
+ };
+
+ AsyncLayerTreeFrameSink(
+ scoped_refptr<viz::ContextProvider> context_provider,
+ scoped_refptr<viz::RasterContextProvider> worker_context_provider,
+ InitParams* params);
+
+ ~AsyncLayerTreeFrameSink() override;
+
+ const viz::HitTestDataProvider* hit_test_data_provider() const {
+ return hit_test_data_provider_.get();
+ }
+
+ const viz::LocalSurfaceId& local_surface_id() const {
+ return local_surface_id_;
+ }
+
+ // LayerTreeFrameSink implementation.
+ bool BindToClient(LayerTreeFrameSinkClient* client) override;
+ void DetachFromClient() override;
+ void SetLocalSurfaceId(const viz::LocalSurfaceId& local_surface_id) override;
+ void SubmitCompositorFrame(viz::CompositorFrame frame) override;
+ void DidNotProduceFrame(const viz::BeginFrameAck& ack) override;
+ void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
+ const viz::SharedBitmapId& id) override;
+ void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override;
+
+ private:
+ // mojom::CompositorFrameSinkClient implementation:
+ void DidReceiveCompositorFrameAck(
+ const std::vector<viz::ReturnedResource>& resources) override;
+ void DidPresentCompositorFrame(
+ uint32_t presentation_token,
+ const gfx::PresentationFeedback& feedback) override;
+ void OnBeginFrame(const viz::BeginFrameArgs& begin_frame_args) override;
+ void OnBeginFramePausedChanged(bool paused) override;
+ void ReclaimResources(
+ const std::vector<viz::ReturnedResource>& resources) override;
+
+ // ExternalBeginFrameSourceClient implementation.
+ void OnNeedsBeginFrames(bool needs_begin_frames) override;
+
+ void OnMojoConnectionError(uint32_t custom_reason,
+ const std::string& description);
+
+ bool begin_frames_paused_ = false;
+ bool needs_begin_frames_ = false;
+ viz::LocalSurfaceId local_surface_id_;
+ std::unique_ptr<viz::HitTestDataProvider> hit_test_data_provider_;
+ std::unique_ptr<viz::LocalSurfaceIdProvider> local_surface_id_provider_;
+ std::unique_ptr<viz::ExternalBeginFrameSource> begin_frame_source_;
+ std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_begin_frame_source_;
+
+ // Message pipes that will be bound when BindToClient() is called.
+ UnboundMessagePipes pipes_;
+
+ // One of |compositor_frame_sink_| or |compositor_frame_sink_associated_| will
+ // be bound after calling BindToClient(). |compositor_frame_sink_ptr_| will
+ // point to message pipe we want to use.
+ viz::mojom::CompositorFrameSink* compositor_frame_sink_ptr_ = nullptr;
+ viz::mojom::CompositorFrameSinkPtr compositor_frame_sink_;
+ viz::mojom::CompositorFrameSinkAssociatedPtr
+ compositor_frame_sink_associated_;
+ mojo::Binding<viz::mojom::CompositorFrameSinkClient> client_binding_;
+
+ THREAD_CHECKER(thread_checker_);
+ const bool enable_surface_synchronization_;
+ const bool wants_animate_only_begin_frames_;
+
+ viz::LocalSurfaceId last_submitted_local_surface_id_;
+ float last_submitted_device_scale_factor_ = 1.f;
+ gfx::Size last_submitted_size_in_pixels_;
+
+ base::WeakPtrFactory<AsyncLayerTreeFrameSink> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncLayerTreeFrameSink);
+};
+
+} // namespace mojo_embedder
+} // namespace cc
+
+#endif // CC_MOJO_EMBEDDER_ASYNC_LAYER_TREE_FRAME_SINK_H_
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
new file mode 100644
index 00000000000..70643db040a
--- /dev/null
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright 2017 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/mojo_embedder/async_layer_tree_frame_sink.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread.h"
+#include "cc/test/fake_layer_tree_frame_sink_client.h"
+#include "components/viz/client/local_surface_id_provider.h"
+#include "components/viz/test/test_context_provider.h"
+#include "components/viz/test/test_gpu_memory_buffer_manager.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace mojo_embedder {
+namespace {
+
+// Used to track the thread DidLoseLayerTreeFrameSink() is called on (and quit
+// a RunLoop).
+class ThreadTrackingLayerTreeFrameSinkClient
+ : public FakeLayerTreeFrameSinkClient {
+ public:
+ ThreadTrackingLayerTreeFrameSinkClient(
+ base::PlatformThreadId* called_thread_id,
+ base::RunLoop* run_loop)
+ : called_thread_id_(called_thread_id), run_loop_(run_loop) {}
+ ~ThreadTrackingLayerTreeFrameSinkClient() override = default;
+
+ // FakeLayerTreeFrameSinkClient:
+ void DidLoseLayerTreeFrameSink() override {
+ EXPECT_FALSE(did_lose_layer_tree_frame_sink_called());
+ FakeLayerTreeFrameSinkClient::DidLoseLayerTreeFrameSink();
+ *called_thread_id_ = base::PlatformThread::CurrentId();
+ run_loop_->Quit();
+ }
+
+ private:
+ base::PlatformThreadId* called_thread_id_;
+ base::RunLoop* run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadTrackingLayerTreeFrameSinkClient);
+};
+
+TEST(AsyncLayerTreeFrameSinkTest,
+ DidLoseLayerTreeFrameSinkCalledOnConnectionError) {
+ base::Thread bg_thread("BG Thread");
+ bg_thread.Start();
+
+ scoped_refptr<viz::TestContextProvider> provider =
+ viz::TestContextProvider::Create();
+ viz::TestGpuMemoryBufferManager test_gpu_memory_buffer_manager;
+
+ viz::mojom::CompositorFrameSinkPtrInfo sink_info;
+ viz::mojom::CompositorFrameSinkRequest sink_request =
+ mojo::MakeRequest(&sink_info);
+ viz::mojom::CompositorFrameSinkClientPtr client;
+ viz::mojom::CompositorFrameSinkClientRequest client_request =
+ mojo::MakeRequest(&client);
+
+ AsyncLayerTreeFrameSink::InitParams init_params;
+ init_params.compositor_task_runner = bg_thread.task_runner();
+ init_params.gpu_memory_buffer_manager = &test_gpu_memory_buffer_manager;
+ init_params.pipes.compositor_frame_sink_info = std::move(sink_info);
+ init_params.pipes.client_request = std::move(client_request);
+ init_params.local_surface_id_provider =
+ std::make_unique<viz::DefaultLocalSurfaceIdProvider>();
+ init_params.enable_surface_synchronization = true;
+ AsyncLayerTreeFrameSink layer_tree_frame_sink(std::move(provider), nullptr,
+ &init_params);
+
+ base::PlatformThreadId called_thread_id = base::kInvalidThreadId;
+ base::RunLoop close_run_loop;
+ ThreadTrackingLayerTreeFrameSinkClient frame_sink_client(&called_thread_id,
+ &close_run_loop);
+
+ auto bind_in_background =
+ [](AsyncLayerTreeFrameSink* layer_tree_frame_sink,
+ ThreadTrackingLayerTreeFrameSinkClient* frame_sink_client) {
+ layer_tree_frame_sink->BindToClient(frame_sink_client);
+ };
+ bg_thread.task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(bind_in_background,
+ base::Unretained(&layer_tree_frame_sink),
+ base::Unretained(&frame_sink_client)));
+ // Closes the pipe, which should trigger calling DidLoseLayerTreeFrameSink()
+ // (and quitting the RunLoop). There is no need to wait for BindToClient()
+ // to complete as mojo::Binding error callbacks are processed asynchronously.
+ sink_request = viz::mojom::CompositorFrameSinkRequest();
+ close_run_loop.Run();
+
+ EXPECT_NE(base::kInvalidThreadId, called_thread_id);
+ EXPECT_EQ(called_thread_id, bg_thread.GetThreadId());
+
+ // DetachFromClient() has to be called on the background thread.
+ base::RunLoop detach_run_loop;
+ auto detach_in_background = [](AsyncLayerTreeFrameSink* layer_tree_frame_sink,
+ base::RunLoop* detach_run_loop) {
+ layer_tree_frame_sink->DetachFromClient();
+ detach_run_loop->Quit();
+ };
+ bg_thread.task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(detach_in_background,
+ base::Unretained(&layer_tree_frame_sink),
+ base::Unretained(&detach_run_loop)));
+ detach_run_loop.Run();
+}
+
+} // namespace
+} // namespace mojo_embedder
+} // namespace cc
diff --git a/chromium/cc/mojo_embedder/mojo_embedder_export.h b/chromium/cc/mojo_embedder/mojo_embedder_export.h
new file mode 100644
index 00000000000..2eb16adbd7c
--- /dev/null
+++ b/chromium/cc/mojo_embedder/mojo_embedder_export.h
@@ -0,0 +1,29 @@
+// Copyright 2017 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_MOJO_EMBEDDER_MOJO_EMBEDDER_EXPORT_H_
+#define CC_MOJO_EMBEDDER_MOJO_EMBEDDER_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(CC_MOJO_EMBEDDER_IMPLEMENTATION)
+#define CC_MOJO_EMBEDDER_EXPORT __declspec(dllexport)
+#else
+#define CC_MOJO_EMBEDDER_EXPORT __declspec(dllimport)
+#endif // defined(CC_MOJO_EMBEDDER_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(CC_MOJO_EMBEDDER_IMPLEMENTATION)
+#define CC_MOJO_EMBEDDER_EXPORT __attribute__((visibility("default")))
+#else
+#define CC_MOJO_EMBEDDER_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define CC_MOJO_EMBEDDER_EXPORT
+#endif
+
+#endif // CC_MOJO_EMBEDDER_MOJO_EMBEDDER_EXPORT_H_
diff --git a/chromium/cc/paint/decoded_draw_image.cc b/chromium/cc/paint/decoded_draw_image.cc
index acc0a263b63..32571f3efb3 100644
--- a/chromium/cc/paint/decoded_draw_image.cc
+++ b/chromium/cc/paint/decoded_draw_image.cc
@@ -22,11 +22,13 @@ DecodedDrawImage::DecodedDrawImage(
const SkSize& src_rect_offset,
const SkSize& scale_adjustment,
SkFilterQuality filter_quality,
+ bool needs_mips,
bool is_budgeted)
: transfer_cache_entry_id_(transfer_cache_entry_id),
src_rect_offset_(src_rect_offset),
scale_adjustment_(scale_adjustment),
filter_quality_(filter_quality),
+ transfer_cache_entry_needs_mips_(needs_mips),
is_budgeted_(is_budgeted) {}
DecodedDrawImage::DecodedDrawImage()
diff --git a/chromium/cc/paint/decoded_draw_image.h b/chromium/cc/paint/decoded_draw_image.h
index c9f0d3fe23d..3079fc48b9c 100644
--- a/chromium/cc/paint/decoded_draw_image.h
+++ b/chromium/cc/paint/decoded_draw_image.h
@@ -28,6 +28,7 @@ class CC_PAINT_EXPORT DecodedDrawImage {
const SkSize& src_rect_offset,
const SkSize& scale_adjustment,
SkFilterQuality filter_quality,
+ bool needs_mips,
bool is_budgeted);
DecodedDrawImage(const DecodedDrawImage& other);
DecodedDrawImage();
@@ -44,6 +45,9 @@ class CC_PAINT_EXPORT DecodedDrawImage {
return std::abs(scale_adjustment_.width() - 1.f) < FLT_EPSILON &&
std::abs(scale_adjustment_.height() - 1.f) < FLT_EPSILON;
}
+ bool transfer_cache_entry_needs_mips() const {
+ return transfer_cache_entry_needs_mips_;
+ }
bool is_budgeted() const { return is_budgeted_; }
private:
@@ -52,6 +56,7 @@ class CC_PAINT_EXPORT DecodedDrawImage {
SkSize src_rect_offset_;
SkSize scale_adjustment_;
SkFilterQuality filter_quality_;
+ bool transfer_cache_entry_needs_mips_ = false;
bool is_budgeted_;
};
diff --git a/chromium/cc/paint/display_item_list.cc b/chromium/cc/paint/display_item_list.cc
index 21e5044b906..cc8db474af3 100644
--- a/chromium/cc/paint/display_item_list.cc
+++ b/chromium/cc/paint/display_item_list.cc
@@ -56,7 +56,8 @@ void DisplayItemList::Raster(SkCanvas* canvas,
}
void DisplayItemList::Finalize() {
- TRACE_EVENT0("cc", "DisplayItemList::Finalize");
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "DisplayItemList::Finalize");
#if DCHECK_IS_ON()
// If this fails a call to StartPaint() was not ended.
DCHECK(!IsPainting());
diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc
index 493a9840a18..fe63071a29f 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.cc
+++ b/chromium/cc/paint/image_transfer_cache_entry.cc
@@ -4,6 +4,7 @@
#include "cc/paint/image_transfer_cache_entry.h"
+#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/numerics/checked_math.h"
#include "cc/paint/paint_op_reader.h"
@@ -11,13 +12,56 @@
#include "third_party/skia/include/gpu/GrContext.h"
namespace cc {
+namespace {
+
+// 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,
+ sk_sp<SkImage> source_image,
+ sk_sp<SkColorSpace> target_color_space,
+ GrMipMapped mip_mapped) {
+ // Step 1: Upload image and generate mips if necessary. If we will be applying
+ // a color-space conversion, don't generate mips yet, instead do it after
+ // conversion, in step 3.
+ // NOTE: |target_color_space| is only passed over the transfer cache if needed
+ // (non-null, different from the source color space).
+ bool add_mips_after_color_conversion =
+ target_color_space && mip_mapped == GrMipMapped::kYes;
+ sk_sp<SkImage> uploaded_image = source_image->makeTextureImage(
+ context, nullptr,
+ add_mips_after_color_conversion ? GrMipMapped::kNo : mip_mapped);
+
+ // Step 2: Apply a color-space conversion if necessary.
+ if (uploaded_image && target_color_space) {
+ // TODO(ericrk): consider adding in the DeleteSkImageAndPreventCaching
+ // optimization from GpuImageDecodeCache where we forcefully remove the
+ // intermediate from Skia's cache.
+ uploaded_image = uploaded_image->makeColorSpace(target_color_space);
+ }
+
+ // Step 3: If we had a colorspace conversion, we couldn't mipmap in step 1, so
+ // add mips here.
+ if (uploaded_image && add_mips_after_color_conversion) {
+ // TODO(ericrk): consider adding in the DeleteSkImageAndPreventCaching
+ // optimization from GpuImageDecodeCache where we forcefully remove the
+ // intermediate from Skia's cache.
+ uploaded_image =
+ uploaded_image->makeTextureImage(context, nullptr, GrMipMapped::kYes);
+ }
+
+ return uploaded_image;
+}
+
+} // namespace
ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
const SkPixmap* pixmap,
- const SkColorSpace* target_color_space)
+ const SkColorSpace* target_color_space,
+ bool needs_mips)
: id_(s_next_id_.GetNext()),
pixmap_(pixmap),
- target_color_space_(target_color_space) {
+ target_color_space_(target_color_space),
+ needs_mips_(needs_mips) {
size_t target_color_space_size =
target_color_space ? target_color_space->writeToMemory(nullptr) : 0u;
size_t pixmap_color_space_size =
@@ -25,21 +69,19 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
: 0u;
// Compute and cache the size of the data.
- // We write the following:
- // - Image color type (uint32_t)
- // - Image width (uint32_t)
- // - Image height (uint32_t)
- // - Pixels size (uint32_t)
- // - Pixels (variable)
base::CheckedNumeric<size_t> safe_size;
+ safe_size += PaintOpWriter::HeaderBytes();
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(size_t); // pixels size
- safe_size += pixmap_->computeByteSize();
- safe_size += PaintOpWriter::HeaderBytes();
safe_size += target_color_space_size + sizeof(size_t);
safe_size += pixmap_color_space_size + sizeof(size_t);
+ // Include 4 bytes of padding so we can always align our data pointer to a
+ // 4-byte boundary.
+ safe_size += 4;
+ safe_size += pixmap_->computeByteSize();
size_ = safe_size.ValueOrDie();
}
@@ -62,18 +104,22 @@ bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const {
// 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,
- false, SkMatrix::I());
+ false, false, 0, 0, SkMatrix::I());
PaintOpWriter writer(data.data(), data.size(), options);
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();
writer.WriteSize(pixmap_size);
// TODO(enne): we should consider caching these in some form.
writer.Write(pixmap_->colorSpace());
writer.Write(target_color_space_);
+ writer.AlignMemory(4);
writer.WriteData(pixmap_size, pixmap_->addr());
- if (writer.size() != data.size())
+
+ // Size can't be 0 after serialization unless the writer has become invalid.
+ if (writer.size() == 0u)
return false;
return true;
@@ -94,6 +140,8 @@ size_t ServiceImageTransferCacheEntry::CachedSize() const {
bool ServiceImageTransferCacheEntry::Deserialize(
GrContext* context,
base::span<const uint8_t> data) {
+ context_ = context;
+
// We don't need to populate the DeSerializeOptions here since the reader is
// only used for de-serializing primitives.
PaintOp::DeserializeOptions options(nullptr, nullptr);
@@ -104,6 +152,9 @@ bool ServiceImageTransferCacheEntry::Deserialize(
reader.Read(&width);
uint32_t height;
reader.Read(&height);
+ uint32_t needs_mips;
+ reader.Read(&needs_mips);
+ has_mips_ = needs_mips;
size_t pixel_size;
reader.ReadSize(&pixel_size);
size_ = data.size();
@@ -119,10 +170,15 @@ bool ServiceImageTransferCacheEntry::Deserialize(
width, height, color_type, kPremul_SkAlphaType, pixmap_color_space);
if (image_info.computeMinByteSize() > pixel_size)
return false;
+
+ // Align data to a 4-byte boundry, to match what we did when writing.
+ reader.AlignMemory(4);
const volatile void* pixel_data = reader.ExtractReadableMemory(pixel_size);
if (!reader.valid())
return false;
+ DCHECK(SkIsAlign4(reinterpret_cast<uintptr_t>(pixel_data)));
+
// 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.
@@ -132,26 +188,21 @@ bool ServiceImageTransferCacheEntry::Deserialize(
// Depending on whether the pixmap will fit in a GPU texture, either create
// a software or GPU SkImage.
uint32_t max_size = context->maxTextureSize();
- bool fits_on_gpu = width <= max_size && height <= max_size;
- if (fits_on_gpu) {
+ fits_on_gpu_ = width <= max_size && height <= max_size;
+ if (fits_on_gpu_) {
sk_sp<SkImage> image = SkImage::MakeFromRaster(pixmap, nullptr, nullptr);
if (!image)
return false;
- image_ = image->makeTextureImage(context, nullptr);
- if (!image_)
- return false;
- if (target_color_space) {
- image_ = image_->makeColorSpace(target_color_space,
- SkTransferFunctionBehavior::kIgnore);
- }
+ image_ =
+ MakeTextureImage(context, std::move(image), target_color_space,
+ needs_mips ? GrMipMapped::kYes : GrMipMapped::kNo);
} else {
sk_sp<SkImage> original =
SkImage::MakeFromRaster(pixmap, [](const void*, void*) {}, nullptr);
if (!original)
return false;
if (target_color_space) {
- image_ = original->makeColorSpace(target_color_space,
- SkTransferFunctionBehavior::kIgnore);
+ image_ = original->makeColorSpace(target_color_space);
// If color space conversion is a noop, use original data.
if (image_ == original)
image_ = SkImage::MakeRasterCopy(pixmap);
@@ -161,10 +212,18 @@ bool ServiceImageTransferCacheEntry::Deserialize(
}
}
- // TODO(enne): consider adding in the DeleteSkImageAndPreventCaching
+ return !!image_;
+}
+
+void ServiceImageTransferCacheEntry::EnsureMips() {
+ if (has_mips_)
+ return;
+
+ has_mips_ = true;
+ // TODO(ericrk): consider adding in the DeleteSkImageAndPreventCaching
// optimization from GpuImageDecodeCache where we forcefully remove the
// intermediate from Skia's cache.
- return image_;
+ image_ = image_->makeTextureImage(context_, nullptr, GrMipMapped::kYes);
}
} // namespace cc
diff --git a/chromium/cc/paint/image_transfer_cache_entry.h b/chromium/cc/paint/image_transfer_cache_entry.h
index 3e709cafd64..db31ade3796 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.h
+++ b/chromium/cc/paint/image_transfer_cache_entry.h
@@ -23,9 +23,9 @@ static constexpr uint32_t kInvalidImageTransferCacheEntryId =
class CC_PAINT_EXPORT ClientImageTransferCacheEntry
: public ClientTransferCacheEntryBase<TransferCacheEntryType::kImage> {
public:
- explicit ClientImageTransferCacheEntry(
- const SkPixmap* pixmap,
- const SkColorSpace* target_color_space);
+ explicit ClientImageTransferCacheEntry(const SkPixmap* pixmap,
+ const SkColorSpace* target_color_space,
+ bool needs_mips);
~ClientImageTransferCacheEntry() final;
uint32_t Id() const final;
@@ -38,6 +38,7 @@ class CC_PAINT_EXPORT ClientImageTransferCacheEntry
uint32_t id_;
const SkPixmap* const pixmap_;
const SkColorSpace* const target_color_space_;
+ const bool needs_mips_;
size_t size_ = 0;
static base::AtomicSequenceNumber s_next_id_;
};
@@ -56,11 +57,18 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry
size_t CachedSize() const final;
bool Deserialize(GrContext* context, base::span<const uint8_t> data) final;
- const sk_sp<SkImage>& image() { return image_; }
+ bool fits_on_gpu() const { return fits_on_gpu_; }
+ const sk_sp<SkImage>& image() const { return image_; }
+
+ // Ensures the cached image has mips.
+ void EnsureMips();
private:
+ GrContext* context_;
sk_sp<SkImage> image_;
+ bool has_mips_ = false;
size_t size_ = 0;
+ bool fits_on_gpu_ = false;
};
} // namespace cc
diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc
index cb3168a7783..c75a03d6b14 100644
--- a/chromium/cc/paint/oop_pixeltest.cc
+++ b/chromium/cc/paint/oop_pixeltest.cc
@@ -8,6 +8,7 @@
#include "base/command_line.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "cc/base/completion_event.h"
#include "cc/base/region.h"
#include "cc/layers/recording_source.h"
#include "cc/paint/display_item_list.h"
@@ -28,6 +29,7 @@
#include "gpu/ipc/gl_in_process_context.h"
#include "gpu/skia_bindings/grcontext_for_gles2_interface.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
@@ -55,7 +57,7 @@ class OopPixelTest : public testing::Test {
void SetUp() override {
raster_context_provider_ =
base::MakeRefCounted<TestInProcessContextProvider>(
- /*enable_oop_rasterization=*/true);
+ /*enable_oop_rasterization=*/true, /*support_locking=*/true);
const int raster_max_texture_size =
raster_context_provider_->ContextCapabilities().max_texture_size;
oop_image_cache_.reset(new GpuImageDecodeCache(
@@ -64,7 +66,7 @@ class OopPixelTest : public testing::Test {
gles2_context_provider_ =
base::MakeRefCounted<TestInProcessContextProvider>(
- /*enable_oop_rasterization=*/false);
+ /*enable_oop_rasterization=*/false, /*support_locking=*/true);
const int gles2_max_texture_size =
raster_context_provider_->ContextCapabilities().max_texture_size;
gpu_image_cache_.reset(new GpuImageDecodeCache(
@@ -99,6 +101,7 @@ class OopPixelTest : public testing::Test {
bool preclear = false;
SkColor preclear_color;
ImageDecodeCache* image_cache = nullptr;
+ std::vector<scoped_refptr<DisplayItemList>> additional_lists;
};
SkBitmap Raster(scoped_refptr<DisplayItemList> display_item_list,
@@ -126,7 +129,7 @@ class OopPixelTest : public testing::Test {
auto* raster_implementation = raster_context_provider_->RasterInterface();
raster_texture_id = raster_implementation->CreateTexture(
false, gfx::BufferUsage::GPU_READ, viz::ResourceFormat::RGBA_8888);
- raster_implementation->TexStorage2D(raster_texture_id, 1, width, height);
+ raster_implementation->TexStorage2D(raster_texture_id, width, height);
raster_implementation->TexParameteri(raster_texture_id,
GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -135,30 +138,32 @@ class OopPixelTest : public testing::Test {
RasterColorSpace color_space(options.color_space, ++color_space_id_);
+ gpu::Mailbox mailbox;
+ raster_implementation->ProduceTextureDirect(raster_texture_id,
+ mailbox.name);
if (options.preclear) {
raster_implementation->BeginRasterCHROMIUM(
- raster_texture_id, options.preclear_color, options.msaa_sample_count,
- options.use_lcd_text, options.color_type, color_space);
+ options.preclear_color, options.msaa_sample_count,
+ options.use_lcd_text, options.color_type, color_space, mailbox.name);
raster_implementation->EndRasterCHROMIUM();
}
// "Out of process" raster! \o/
raster_implementation->BeginRasterCHROMIUM(
- raster_texture_id, options.background_color, options.msaa_sample_count,
- options.use_lcd_text, options.color_type, color_space);
+ options.background_color, options.msaa_sample_count,
+ options.use_lcd_text, options.color_type, color_space, mailbox.name);
raster_implementation->RasterCHROMIUM(
display_item_list.get(), &image_provider, options.content_size,
options.full_raster_rect, options.playback_rect, options.post_translate,
options.post_scale, options.requires_clear);
+ for (const auto& list : options.additional_lists) {
+ raster_implementation->RasterCHROMIUM(
+ list.get(), &image_provider, options.content_size,
+ options.full_raster_rect, options.playback_rect,
+ options.post_translate, options.post_scale, options.requires_clear);
+ }
raster_implementation->EndRasterCHROMIUM();
-
- // Produce a mailbox and insert an ordering barrier (assumes the raster
- // interface and gl are on the same scheduling group).
- gpu::Mailbox mailbox;
- raster_implementation->GenMailbox(mailbox.name);
- raster_implementation->ProduceTextureDirect(raster_texture_id,
- mailbox.name);
raster_implementation->OrderingBarrierCHROMIUM();
EXPECT_EQ(raster_implementation->GetError(),
@@ -319,6 +324,12 @@ class OopImagePixelTest : public OopPixelTest,
}
};
+class OopClearPixelTest : public OopPixelTest,
+ public ::testing::WithParamInterface<bool> {
+ public:
+ bool IsPartialRaster() const { return GetParam(); }
+};
+
TEST_F(OopPixelTest, DrawColor) {
gfx::Rect rect(10, 10);
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
@@ -572,6 +583,50 @@ TEST_P(OopImagePixelTest, DrawRecordShaderWithImageScaled) {
ExpectEquals(actual, expected);
}
+TEST_F(OopImagePixelTest, DrawRecordShaderTranslatedTileRect) {
+ auto paint_record = sk_make_sp<PaintOpBuffer>();
+
+ // Arbitrary offsets. The DrawRectOp inside the PaintShader draws
+ // with this offset, but the tile rect also has this offset, so they
+ // should cancel out, and it should be as if the DrawRectOp was at the
+ // origin.
+ int x_offset = 3901;
+ int y_offset = -234;
+
+ // Shader here is a tiled 2x3 rectangle with a 1x2 green block in the
+ // upper left and a 10pixel wide right/bottom border. The shader
+ // tiling starts from the origin, so starting at 2,1 in the offset_rect
+ // below cuts off part of that, leaving two green i's.
+ PaintFlags internal_flags;
+ internal_flags.setColor(SK_ColorGREEN);
+ sk_sp<PaintOpBuffer> shader_buffer(new PaintOpBuffer);
+ shader_buffer->push<DrawRectOp>(SkRect::MakeXYWH(x_offset, y_offset, 1, 2),
+ internal_flags);
+
+ SkRect tile_rect = SkRect::MakeXYWH(x_offset, y_offset, 2, 3);
+ sk_sp<PaintShader> paint_record_shader = PaintShader::MakePaintRecord(
+ shader_buffer, tile_rect, SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode, nullptr,
+ PaintShader::ScalingBehavior::kRasterAtScale);
+
+ gfx::Size output_size(10, 10);
+
+ auto display_item_list = base::MakeRefCounted<DisplayItemList>();
+ display_item_list->StartPaint();
+ display_item_list->push<DrawColorOp>(SK_ColorWHITE, SkBlendMode::kSrc);
+ display_item_list->push<ScaleOp>(2.f, 2.f);
+ PaintFlags raster_flags;
+ raster_flags.setShader(paint_record_shader);
+ SkRect offset_rect = SkRect::MakeXYWH(2, 1, 10, 10);
+ display_item_list->push<DrawRectOp>(offset_rect, raster_flags);
+ display_item_list->EndPaintOfUnpaired(gfx::Rect(output_size));
+ display_item_list->Finalize();
+
+ auto actual = Raster(display_item_list, output_size);
+ auto expected = RasterExpectedBitmap(display_item_list, output_size);
+ ExpectEquals(actual, expected);
+}
+
TEST_P(OopImagePixelTest, DrawImageWithTargetColorSpace) {
SCOPED_TRACE(base::StringPrintf("UseTooLargeImage: %d, FilterQuality: %d\n",
UseTooLargeImage(), FilterQuality()));
@@ -724,7 +779,7 @@ TEST_F(OopPixelTest, Preclear) {
ExpectEquals(actual, expected);
}
-TEST_F(OopPixelTest, ClearingOpaqueCorner) {
+TEST_P(OopClearPixelTest, ClearingOpaqueCorner) {
// Verify that clears work properly for both the right and bottom sides
// of an opaque corner tile.
@@ -734,7 +789,14 @@ TEST_F(OopPixelTest, ClearingOpaqueCorner) {
options.full_raster_rect = gfx::Rect(arbitrary_offset, gfx::Size(8, 7));
options.content_size = gfx::Size(options.full_raster_rect.right(),
options.full_raster_rect.bottom());
- options.playback_rect = options.full_raster_rect;
+ if (IsPartialRaster()) {
+ options.playback_rect = gfx::Rect(options.full_raster_rect.x() + 1,
+ options.full_raster_rect.y() + 1,
+ options.full_raster_rect.width() - 1,
+ options.full_raster_rect.height() - 1);
+ } else {
+ options.playback_rect = options.full_raster_rect;
+ }
options.background_color = SK_ColorGREEN;
float arbitrary_scale = 0.25f;
options.post_scale = arbitrary_scale;
@@ -754,13 +816,20 @@ TEST_F(OopPixelTest, ClearingOpaqueCorner) {
options.resource_size.height()),
SkBitmap::kZeroPixels_AllocFlag);
- // Expect a two pixel border from texels 7-9 on the column and 6-8 on row.
SkCanvas canvas(bitmap);
canvas.drawColor(options.preclear_color);
SkPaint green;
green.setColor(options.background_color);
- canvas.drawRect(SkRect::MakeXYWH(7, 0, 2, 8), green);
- canvas.drawRect(SkRect::MakeXYWH(0, 6, 9, 2), green);
+ if (IsPartialRaster()) {
+ // Expect a two pixel border from texels 7-9 on the column and 6-8 on row,
+ // ignoring the top row and left column.
+ canvas.drawRect(SkRect::MakeXYWH(7, 1, 2, 7), green);
+ canvas.drawRect(SkRect::MakeXYWH(1, 6, 8, 2), green);
+ } else {
+ // Expect a two pixel border from texels 7-9 on the column and 6-8 on row.
+ canvas.drawRect(SkRect::MakeXYWH(7, 0, 2, 8), green);
+ canvas.drawRect(SkRect::MakeXYWH(0, 6, 9, 2), green);
+ }
ExpectEquals(oop_result, bitmap, "oop");
ExpectEquals(gpu_result, bitmap, "gpu");
@@ -820,12 +889,16 @@ TEST_F(OopPixelTest, ClearingOpaqueCornerPartialRaster) {
options.content_size = gfx::Size(options.full_raster_rect.right(),
options.full_raster_rect.bottom());
options.playback_rect =
- gfx::Rect(arbitrary_offset.x() + 5, arbitrary_offset.y() + 3, 2, 4);
+ gfx::Rect(arbitrary_offset.x() + 5, arbitrary_offset.y() + 3, 2, 3);
options.background_color = SK_ColorGREEN;
options.requires_clear = false;
options.preclear = true;
options.preclear_color = SK_ColorRED;
+ // Verify this is internal.
+ EXPECT_NE(options.playback_rect.right(), options.full_raster_rect.right());
+ EXPECT_NE(options.playback_rect.bottom(), options.full_raster_rect.bottom());
+
// Make a non-empty but noop display list to avoid early outs.
auto display_item_list = MakeNoopDisplayItemList();
@@ -846,17 +919,27 @@ TEST_F(OopPixelTest, ClearingOpaqueCornerPartialRaster) {
ExpectEquals(gpu_result, bitmap, "gpu");
}
-TEST_F(OopPixelTest, ClearingOpaqueRightEdge) {
+TEST_P(OopClearPixelTest, ClearingOpaqueRightEdge) {
// Verify that a tile that intersects the right edge of content
// but not the bottom only clears the right pixels.
-
RasterOptions options;
gfx::Point arbitrary_offset(30, 40);
options.resource_size = gfx::Size(10, 10);
options.full_raster_rect = gfx::Rect(arbitrary_offset, gfx::Size(3, 10));
options.content_size = gfx::Size(options.full_raster_rect.right(),
options.full_raster_rect.bottom() + 1000);
- options.playback_rect = options.full_raster_rect;
+ if (IsPartialRaster()) {
+ // Ignore the left column of pixels here to force partial raster.
+ // Additionally ignore the bottom row of pixels to make sure
+ // that things are not cleared outside the rect.
+ options.playback_rect = gfx::Rect(options.full_raster_rect.x() + 1,
+ options.full_raster_rect.y(),
+ options.full_raster_rect.width() - 1,
+ options.full_raster_rect.height() - 1);
+ } else {
+ options.playback_rect = options.full_raster_rect;
+ }
+
options.background_color = SK_ColorGREEN;
options.requires_clear = false;
options.preclear = true;
@@ -874,18 +957,23 @@ TEST_F(OopPixelTest, ClearingOpaqueRightEdge) {
options.resource_size.height()),
SkBitmap::kZeroPixels_AllocFlag);
- // Expect a two pixel column border from texels 2-4.
SkCanvas canvas(bitmap);
canvas.drawColor(options.preclear_color);
SkPaint green;
green.setColor(options.background_color);
- canvas.drawRect(SkRect::MakeXYWH(2, 0, 2, 10), green);
+ if (IsPartialRaster()) {
+ // Expect a two pixel column border from texels 2-4, ignoring the last row.
+ canvas.drawRect(SkRect::MakeXYWH(2, 0, 2, 9), green);
+ } else {
+ // Expect a two pixel column border from texels 2-4.
+ canvas.drawRect(SkRect::MakeXYWH(2, 0, 2, 10), green);
+ }
ExpectEquals(oop_result, bitmap, "oop");
ExpectEquals(gpu_result, bitmap, "gpu");
}
-TEST_F(OopPixelTest, ClearingOpaqueBottomEdge) {
+TEST_P(OopClearPixelTest, ClearingOpaqueBottomEdge) {
// Verify that a tile that intersects the bottom edge of content
// but not the right only clears the bottom pixels.
@@ -895,7 +983,17 @@ TEST_F(OopPixelTest, ClearingOpaqueBottomEdge) {
options.full_raster_rect = gfx::Rect(arbitrary_offset, gfx::Size(10, 5));
options.content_size = gfx::Size(options.full_raster_rect.right() + 1000,
options.full_raster_rect.bottom());
- options.playback_rect = options.full_raster_rect;
+ if (IsPartialRaster()) {
+ // Ignore the top row of pixels here to force partial raster.
+ // Additionally ignore the right column of pixels to make sure
+ // that things are not cleared outside the rect.
+ options.playback_rect = gfx::Rect(options.full_raster_rect.x(),
+ options.full_raster_rect.y() + 1,
+ options.full_raster_rect.width() - 1,
+ options.full_raster_rect.height() - 1);
+ } else {
+ options.playback_rect = options.full_raster_rect;
+ }
options.background_color = SK_ColorGREEN;
float arbitrary_scale = 0.25f;
options.post_scale = arbitrary_scale;
@@ -915,12 +1013,19 @@ TEST_F(OopPixelTest, ClearingOpaqueBottomEdge) {
options.resource_size.height()),
SkBitmap::kZeroPixels_AllocFlag);
- // Expect a two pixel border from texels 4-6 on the row
SkCanvas canvas(bitmap);
canvas.drawColor(options.preclear_color);
SkPaint green;
green.setColor(options.background_color);
- canvas.drawRect(SkRect::MakeXYWH(0, 4, 10, 2), green);
+
+ if (IsPartialRaster()) {
+ // Expect a two pixel border from texels 4-6 on the row, ignoring the last
+ // column.
+ canvas.drawRect(SkRect::MakeXYWH(0, 4, 9, 2), green);
+ } else {
+ // Expect a two pixel border from texels 4-6 on the row
+ canvas.drawRect(SkRect::MakeXYWH(0, 4, 10, 2), green);
+ }
ExpectEquals(oop_result, bitmap, "oop");
ExpectEquals(gpu_result, bitmap, "gpu");
@@ -1200,10 +1305,12 @@ TEST_F(OopPixelTest, DrawRectColorSpace) {
ExpectEquals(actual, expected);
}
-scoped_refptr<PaintTextBlob> buildTextBlob() {
+scoped_refptr<PaintTextBlob> BuildTextBlob(
+ PaintTypeface typeface = PaintTypeface()) {
SkFontStyle style;
- PaintTypeface typeface =
- PaintTypeface::FromFamilyNameAndFontStyle("monospace", style);
+ if (!typeface) {
+ typeface = PaintTypeface::FromFamilyNameAndFontStyle("monospace", style);
+ }
PaintFont font;
font.SetTypeface(typeface);
@@ -1235,7 +1342,7 @@ TEST_F(OopPixelTest, DrawTextBlob) {
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
flags.setColor(SK_ColorGREEN);
- display_item_list->push<DrawTextBlobOp>(buildTextBlob(), 0u, 0u, flags);
+ display_item_list->push<DrawTextBlobOp>(BuildTextBlob(), 0u, 0u, flags);
display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
display_item_list->Finalize();
@@ -1256,7 +1363,7 @@ TEST_F(OopPixelTest, DrawRecordShaderWithTextScaled) {
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
flags.setColor(SK_ColorGREEN);
- paint_record->push<DrawTextBlobOp>(buildTextBlob(), 0u, 0u, flags);
+ paint_record->push<DrawTextBlobOp>(BuildTextBlob(), 0u, 0u, flags);
auto paint_record_shader = PaintShader::MakePaintRecord(
paint_record, SkRect::MakeWH(25, 25), SkShader::kRepeat_TileMode,
SkShader::kRepeat_TileMode, nullptr);
@@ -1287,7 +1394,7 @@ TEST_F(OopPixelTest, DrawRecordFilterWithTextScaled) {
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
flags.setColor(SK_ColorGREEN);
- paint_record->push<DrawTextBlobOp>(buildTextBlob(), 0u, 0u, flags);
+ paint_record->push<DrawTextBlobOp>(BuildTextBlob(), 0u, 0u, flags);
auto paint_record_filter =
sk_make_sp<RecordPaintFilter>(paint_record, SkRect::MakeWH(100, 100));
@@ -1305,7 +1412,59 @@ TEST_F(OopPixelTest, DrawRecordFilterWithTextScaled) {
ExpectEquals(actual, expected);
}
+void ClearFontCache(CompletionEvent* event) {
+ SkGraphics::PurgeFontCache();
+ event->Signal();
+}
+
+TEST_F(OopPixelTest, DrawTextMultipleRasterCHROMIUM) {
+ RasterOptions options;
+ options.resource_size = gfx::Size(100, 100);
+ options.content_size = options.resource_size;
+ options.full_raster_rect = gfx::Rect(options.content_size);
+ options.playback_rect = options.full_raster_rect;
+ options.color_space = gfx::ColorSpace::CreateSRGB();
+
+ auto sk_typeface_1 = SkTypeface::MakeFromName("monospace", SkFontStyle());
+ auto sk_typeface_2 = SkTypeface::MakeFromName("roboto", SkFontStyle());
+
+ auto display_item_list = base::MakeRefCounted<DisplayItemList>();
+ display_item_list->StartPaint();
+ PaintFlags flags;
+ flags.setStyle(PaintFlags::kFill_Style);
+ flags.setColor(SK_ColorGREEN);
+ display_item_list->push<DrawTextBlobOp>(
+ BuildTextBlob(PaintTypeface::FromSkTypeface(sk_typeface_1)), 0u, 0u,
+ flags);
+ display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
+ display_item_list->Finalize();
+
+ // Create another list with a different typeface.
+ auto display_item_list_2 = base::MakeRefCounted<DisplayItemList>();
+ display_item_list_2->StartPaint();
+ display_item_list_2->push<DrawTextBlobOp>(
+ BuildTextBlob(PaintTypeface::FromSkTypeface(sk_typeface_2)), 0u, 0u,
+ flags);
+ display_item_list_2->EndPaintOfUnpaired(options.full_raster_rect);
+ display_item_list_2->Finalize();
+
+ // Raster both these lists with 2 RasterCHROMIUM commands between a single
+ // Begin/EndRaster sequence.
+ options.additional_lists = {display_item_list_2};
+ Raster(display_item_list, options);
+
+ // Clear skia's font cache. No entries should remain since the service
+ // should unpin everything.
+ EXPECT_GT(SkGraphics::GetFontCacheUsed(), 0u);
+ CompletionEvent event;
+ raster_context_provider_->ExecuteOnGpuThread(
+ base::BindOnce(&ClearFontCache, &event));
+ event.Wait();
+ EXPECT_EQ(SkGraphics::GetFontCacheUsed(), 0u);
+}
+
INSTANTIATE_TEST_CASE_P(P, OopImagePixelTest, ::testing::Bool());
+INSTANTIATE_TEST_CASE_P(P, OopClearPixelTest, ::testing::Bool());
} // namespace
} // namespace cc
diff --git a/chromium/cc/paint/paint_canvas.h b/chromium/cc/paint/paint_canvas.h
index c8f959d5067..53bde682c34 100644
--- a/chromium/cc/paint/paint_canvas.h
+++ b/chromium/cc/paint/paint_canvas.h
@@ -132,13 +132,6 @@ class CC_PAINT_EXPORT PaintCanvas {
const SkRect& dst,
const PaintFlags* flags,
SrcRectConstraint constraint) = 0;
- virtual void drawBitmap(const SkBitmap& bitmap,
- SkScalar left,
- SkScalar top,
- const PaintFlags* flags) = 0;
- void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top) {
- drawBitmap(bitmap, left, top, nullptr);
- }
virtual void drawTextBlob(scoped_refptr<PaintTextBlob> blob,
SkScalar x,
diff --git a/chromium/cc/paint/paint_filter.h b/chromium/cc/paint/paint_filter.h
index cab890edff5..7710d501551 100644
--- a/chromium/cc/paint/paint_filter.h
+++ b/chromium/cc/paint/paint_filter.h
@@ -93,14 +93,6 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
return 0;
return cached_sk_filter_->countInputs();
}
- std::string ToString() const {
- if (!cached_sk_filter_)
- return "Invalid filter";
-
- SkString str;
- cached_sk_filter_->toString(&str);
- return str.c_str();
- }
const CropRect* crop_rect() const {
return base::OptionalOrNullptr(crop_rect_);
}
diff --git a/chromium/cc/paint/paint_image.cc b/chromium/cc/paint/paint_image.cc
index 805520f8b37..34bb6759db0 100644
--- a/chromium/cc/paint/paint_image.cc
+++ b/chromium/cc/paint/paint_image.cc
@@ -8,6 +8,7 @@
#include "base/atomic_sequence_num.h"
#include "base/hash.h"
+#include "cc/paint/paint_image_builder.h"
#include "cc/paint/paint_image_generator.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/skia_paint_image_generator.h"
@@ -82,6 +83,18 @@ PaintImage::ContentId PaintImage::GetNextContentId() {
return g_next_image_content_id.GetNext();
}
+// static
+PaintImage PaintImage::CreateFromBitmap(SkBitmap bitmap) {
+ if (bitmap.drawsNothing())
+ return PaintImage();
+
+ return PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_image(SkImage::MakeFromBitmap(bitmap),
+ PaintImage::GetNextContentId())
+ .TakePaintImage();
+}
+
const sk_sp<SkImage>& PaintImage::GetSkImage() const {
return cached_sk_image_;
}
@@ -137,10 +150,8 @@ SkISize PaintImage::GetSupportedDecodeSize(
// TODO(vmpstr): If this image is using subset_rect, then we don't support
// decoding to any scale other than the original. See the comment in Decode()
// explaining this in more detail.
- // TODO(vmpstr): For now, always decode to the original size. This can be
- // enabled with the following code, and should be done as a follow-up.
- // if (paint_image_generator_ && subset_rect_.IsEmpty())
- // return paint_image_generator_->GetSupportedDecodeSize(requested_size);
+ if (paint_image_generator_ && subset_rect_.IsEmpty())
+ return paint_image_generator_->GetSupportedDecodeSize(requested_size);
return SkISize::Make(width(), height());
}
@@ -217,8 +228,7 @@ bool PaintImage::DecodeFromSkImage(void* memory,
auto image = GetSkImageForFrame(frame_index);
DCHECK(image);
if (color_space) {
- image =
- image->makeColorSpace(color_space, SkTransferFunctionBehavior::kIgnore);
+ image = image->makeColorSpace(color_space);
if (!image)
return false;
}
diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h
index d45fe686ccb..f3f91350d83 100644
--- a/chromium/cc/paint/paint_image.h
+++ b/chromium/cc/paint/paint_image.h
@@ -94,6 +94,10 @@ class CC_PAINT_EXPORT PaintImage {
static Id GetNextId();
static ContentId GetNextContentId();
+ // Creates a PaintImage wrapping |bitmap|. Note that the pixels will be copied
+ // unless the bitmap is marked immutable.
+ static PaintImage CreateFromBitmap(SkBitmap bitmap);
+
PaintImage();
PaintImage(const PaintImage& other);
PaintImage(PaintImage&& other);
@@ -158,6 +162,9 @@ class CC_PAINT_EXPORT PaintImage {
// Returns the total number of frames known to exist in this image.
size_t FrameCount() const;
+ // Returns an SkImage for the frame at |index|.
+ sk_sp<SkImage> GetSkImageForFrame(size_t index) const;
+
std::string ToString() const;
private:
@@ -180,9 +187,6 @@ class CC_PAINT_EXPORT PaintImage {
void CreateSkImage();
PaintImage MakeSubset(const gfx::Rect& subset) const;
- // Returns an SkImage for the frame at |index|.
- sk_sp<SkImage> GetSkImageForFrame(size_t index) const;
-
sk_sp<SkImage> sk_image_;
sk_sp<PaintRecord> paint_record_;
gfx::Rect paint_record_rect_;
diff --git a/chromium/cc/paint/paint_image_unittest.cc b/chromium/cc/paint/paint_image_unittest.cc
index 78a2240bdce..d8c59fcaef7 100644
--- a/chromium/cc/paint/paint_image_unittest.cc
+++ b/chromium/cc/paint/paint_image_unittest.cc
@@ -82,4 +82,27 @@ TEST(PaintImageTest, DecodesCorrectFrames) {
generator->reset_frames_decoded();
}
+TEST(PaintImageTest, SupportedDecodeSize) {
+ SkISize full_size = SkISize::Make(10, 10);
+ std::vector<SkISize> supported_sizes = {SkISize::Make(5, 5)};
+ std::vector<FrameMetadata> frames = {FrameMetadata()};
+ sk_sp<FakePaintImageGenerator> generator =
+ sk_make_sp<FakePaintImageGenerator>(
+ SkImageInfo::MakeN32Premul(full_size.width(), full_size.height()),
+ frames, true, supported_sizes);
+ PaintImage image = PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_frame_index(0u)
+ .TakePaintImage();
+ EXPECT_EQ(image.GetSupportedDecodeSize(supported_sizes[0]),
+ supported_sizes[0]);
+
+ PaintImage subset = PaintImageBuilder::WithCopy(image)
+ .make_subset(gfx::Rect(8, 8))
+ .TakePaintImage();
+ EXPECT_EQ(subset.GetSupportedDecodeSize(supported_sizes[0]),
+ SkISize::Make(8, 8));
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc
index 45ae2526f15..13867d477a2 100644
--- a/chromium/cc/paint/paint_op_buffer.cc
+++ b/chromium/cc/paint/paint_op_buffer.cc
@@ -22,6 +22,8 @@ namespace {
DrawImage CreateDrawImage(const PaintImage& image,
const PaintFlags* flags,
const SkMatrix& matrix) {
+ if (!image)
+ return DrawImage();
return DrawImage(image, SkIRect::MakeWH(image.width(), image.height()),
flags ? flags->getFilterQuality() : kLow_SkFilterQuality,
matrix);
@@ -325,6 +327,9 @@ PaintOp::SerializeOptions::SerializeOptions(
SkStrikeServer* strike_server,
SkColorSpace* color_space,
bool can_use_lcd_text,
+ bool context_supports_distance_field_text,
+ int max_texture_size,
+ size_t max_texture_bytes,
const SkMatrix& original_ctm)
: image_provider(image_provider),
transfer_cache(transfer_cache),
@@ -332,8 +337,16 @@ PaintOp::SerializeOptions::SerializeOptions(
strike_server(strike_server),
color_space(color_space),
can_use_lcd_text(can_use_lcd_text),
+ context_supports_distance_field_text(
+ context_supports_distance_field_text),
+ max_texture_size(max_texture_size),
+ max_texture_bytes(max_texture_bytes),
original_ctm(original_ctm) {}
+PaintOp::SerializeOptions::SerializeOptions(const SerializeOptions&) = default;
+PaintOp::SerializeOptions& PaintOp::SerializeOptions::operator=(
+ const SerializeOptions&) = default;
+
PaintOp::DeserializeOptions::DeserializeOptions(
TransferCacheDeserializeHelper* transfer_cache,
SkStrikeClient* strike_client)
@@ -448,11 +461,14 @@ size_t DrawImageRectOp::Serialize(const PaintOp* base_op,
serialized_flags = &op->flags;
helper.Write(*serialized_flags);
+ // This adjustment mirrors DiscardableImageMap::GatherDiscardableImage logic.
+ SkMatrix matrix = options.canvas->getTotalMatrix();
+ matrix.postConcat(
+ SkMatrix::MakeRectToRect(op->src, op->dst, SkMatrix::kFill_ScaleToFit));
// Note that we don't request subsets here since the GpuImageCache has no
// optimizations for using subsets.
SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
- helper.Write(CreateDrawImage(op->image, serialized_flags,
- options.canvas->getTotalMatrix()),
+ helper.Write(CreateDrawImage(op->image, serialized_flags, matrix),
&scale_adjustment);
helper.AlignMemory(alignof(SkScalar));
helper.Write(scale_adjustment.width());
diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h
index f803f0f27bb..c1477a14281 100644
--- a/chromium/cc/paint/paint_op_buffer.h
+++ b/chromium/cc/paint/paint_op_buffer.h
@@ -146,7 +146,12 @@ class CC_PAINT_EXPORT PaintOp {
SkStrikeServer* strike_server,
SkColorSpace* color_space,
bool can_use_lcd_text,
+ bool context_supports_distance_field_text,
+ int max_texture_size,
+ size_t max_texture_bytes,
const SkMatrix& original_ctm);
+ SerializeOptions(const SerializeOptions&);
+ SerializeOptions& operator=(const SerializeOptions&);
// Required.
ImageProvider* image_provider = nullptr;
@@ -155,9 +160,12 @@ class CC_PAINT_EXPORT PaintOp {
SkStrikeServer* strike_server = nullptr;
SkColorSpace* color_space = nullptr;
bool can_use_lcd_text = false;
+ bool context_supports_distance_field_text = true;
+ int max_texture_size = 0;
+ size_t max_texture_bytes = 0.f;
+ SkMatrix original_ctm = SkMatrix::I();
// Optional.
- SkMatrix original_ctm = SkMatrix::I();
// The flags to use when serializing this op. This can be used to override
// the flags serialized with the op. Valid only for PaintOpWithFlags.
const PaintFlags* flags_to_serialize = nullptr;
@@ -591,7 +599,10 @@ class CC_PAINT_EXPORT DrawOvalOp final : public PaintOpWithFlags {
const PaintFlags* flags,
SkCanvas* canvas,
const PlaybackParams& params);
- bool IsValid() const { return flags.IsValid() && oval.isFinite(); }
+ bool IsValid() const {
+ // Reproduce SkRRect::isValid without converting.
+ return flags.IsValid() && oval.isFinite() && oval.isSorted();
+ }
static bool AreEqual(const PaintOp* left, const PaintOp* right);
HAS_SERIALIZATION_FUNCTIONS();
diff --git a/chromium/cc/paint/paint_op_buffer_fuzzer.cc b/chromium/cc/paint/paint_op_buffer_fuzzer.cc
index dfbbf34c49e..77070e59cec 100644
--- a/chromium/cc/paint/paint_op_buffer_fuzzer.cc
+++ b/chromium/cc/paint/paint_op_buffer_fuzzer.cc
@@ -37,11 +37,12 @@ class FontSupport : public gpu::ServiceFontManager::Client {
private:
scoped_refptr<gpu::Buffer> CreateBuffer(uint32_t shm_id) {
- std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
static const size_t kBufferSize = 2048u;
- shared_memory->CreateAndMapAnonymous(kBufferSize);
- auto buffer =
- gpu::MakeBufferFromSharedMemory(std::move(shared_memory), kBufferSize);
+ base::UnsafeSharedMemoryRegion shared_memory =
+ base::UnsafeSharedMemoryRegion::Create(kBufferSize);
+ base::WritableSharedMemoryMapping mapping = shared_memory.Map();
+ auto buffer = gpu::MakeBufferFromSharedMemory(std::move(shared_memory),
+ std::move(mapping));
buffers_[shm_id] = buffer;
return buffer;
}
@@ -49,37 +50,15 @@ class FontSupport : public gpu::ServiceFontManager::Client {
base::flat_map<uint32_t, scoped_refptr<gpu::Buffer>> buffers_;
};
-// Deserialize an arbitrary number of cc::PaintOps and raster them
-// using gpu raster into an SkCanvas.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- if (size <= sizeof(size_t))
- return 0;
-
- static Environment* env = new Environment();
- ALLOW_UNUSED_LOCAL(env);
- base::CommandLine::Init(0, nullptr);
- const size_t kMaxSerializedSize = 1000000;
+void Raster(scoped_refptr<viz::TestContextProvider> context_provider,
+ SkStrikeClient* strike_client,
+ const uint8_t* data,
+ size_t size) {
const size_t kRasterDimension = 32;
-
- // Partition the data to use some bytes for populating the font cache.
- size_t bytes_for_fonts = data[0];
- if (bytes_for_fonts > size)
- bytes_for_fonts = size / 2;
-
- FontSupport font_support;
- gpu::ServiceFontManager font_manager(&font_support);
- std::vector<SkDiscardableHandleId> locked_handles;
- if (bytes_for_fonts > 0u) {
- font_manager.Deserialize(reinterpret_cast<const char*>(data),
- bytes_for_fonts, &locked_handles);
- data += bytes_for_fonts;
- size -= bytes_for_fonts;
- }
+ const size_t kMaxSerializedSize = 1000000;
SkImageInfo image_info = SkImageInfo::MakeN32(
kRasterDimension, kRasterDimension, kOpaque_SkAlphaType);
- scoped_refptr<viz::TestContextProvider> context_provider =
- viz::TestContextProvider::Create();
context_provider->BindToCurrentThread();
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
context_provider->GrContext(), SkBudgeted::kYes, image_info);
@@ -87,8 +66,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
cc::PlaybackParams params(nullptr, canvas->getTotalMatrix());
cc::TransferCacheTestHelper transfer_cache_helper;
- cc::PaintOp::DeserializeOptions deserialize_options(
- &transfer_cache_helper, font_manager.strike_client());
+ cc::PaintOp::DeserializeOptions deserialize_options(&transfer_cache_helper,
+ strike_client);
// Need 4 bytes to be able to read the type/skip.
while (size >= 4) {
@@ -117,6 +96,45 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
size -= bytes_read;
data += bytes_read;
}
+}
+
+// Deserialize an arbitrary number of cc::PaintOps and raster them
+// using gpu raster into an SkCanvas.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size <= sizeof(size_t))
+ return 0;
+
+ static Environment* env = new Environment();
+ ALLOW_UNUSED_LOCAL(env);
+ base::CommandLine::Init(0, nullptr);
+
+ // Partition the data to use some bytes for populating the font cache.
+ size_t bytes_for_fonts = data[0];
+ if (bytes_for_fonts > size)
+ bytes_for_fonts = size / 2;
+
+ FontSupport font_support;
+ gpu::ServiceFontManager font_manager(&font_support);
+ std::vector<SkDiscardableHandleId> locked_handles;
+ if (bytes_for_fonts > 0u) {
+ font_manager.Deserialize(reinterpret_cast<const char*>(data),
+ bytes_for_fonts, &locked_handles);
+ data += bytes_for_fonts;
+ size -= bytes_for_fonts;
+ }
+
+ auto context_provider_no_support = viz::TestContextProvider::Create();
+ context_provider_no_support->BindToCurrentThread();
+ CHECK(!context_provider_no_support->GrContext()->supportsDistanceFieldText());
+ Raster(context_provider_no_support, font_manager.strike_client(), data, size);
+
+ auto context_provider_with_support = viz::TestContextProvider::Create(
+ std::string("GL_OES_standard_derivatives"));
+ context_provider_with_support->BindToCurrentThread();
+ CHECK(
+ context_provider_with_support->GrContext()->supportsDistanceFieldText());
+ Raster(context_provider_with_support, font_manager.strike_client(), data,
+ size);
font_manager.Unlock(locked_handles);
return 0;
diff --git a/chromium/cc/paint/paint_op_buffer_serializer.cc b/chromium/cc/paint/paint_op_buffer_serializer.cc
index 869d7c5403b..cf4c77a923f 100644
--- a/chromium/cc/paint/paint_op_buffer_serializer.cc
+++ b/chromium/cc/paint/paint_op_buffer_serializer.cc
@@ -25,7 +25,7 @@ class ScopedFlagsOverride {
PaintOp::SerializeOptions* options_;
};
-// Copied from LayerTreeResourceProvider.
+// Copied from viz::ClientResourceProvider.
SkSurfaceProps ComputeSurfaceProps(bool can_use_lcd_text) {
uint32_t flags = 0;
// Use unknown pixel geometry to disable LCD text.
@@ -44,6 +44,18 @@ PlaybackParams MakeParams(const SkCanvas* canvas) {
return PlaybackParams(nullptr, canvas->getTotalMatrix());
}
+SkTextBlobCacheDiffCanvas::Settings MakeCanvasSettings(
+ bool context_supports_distance_field_text,
+ int max_texture_size,
+ size_t max_texture_bytes) {
+ SkTextBlobCacheDiffCanvas::Settings settings;
+ settings.fContextSupportsDistanceFieldText =
+ context_supports_distance_field_text;
+ settings.fMaxTextureSize = max_texture_size;
+ settings.fMaxTextureBytes = max_texture_bytes;
+ return settings;
+}
+
// Use half of the max int as the extent for the SkNoDrawCanvas. The correct
// clip is applied to the canvas during serialization.
const int kMaxExtent = std::numeric_limits<int>::max() >> 1;
@@ -56,18 +68,26 @@ PaintOpBufferSerializer::PaintOpBufferSerializer(
TransferCacheSerializeHelper* transfer_cache,
SkStrikeServer* strike_server,
SkColorSpace* color_space,
- bool can_use_lcd_text)
+ bool can_use_lcd_text,
+ bool context_supports_distance_field_text,
+ int max_texture_size,
+ size_t max_texture_bytes)
: serialize_cb_(std::move(serialize_cb)),
image_provider_(image_provider),
transfer_cache_(transfer_cache),
strike_server_(strike_server),
color_space_(color_space),
can_use_lcd_text_(can_use_lcd_text),
+ context_supports_distance_field_text_(
+ context_supports_distance_field_text),
text_blob_canvas_(kMaxExtent,
kMaxExtent,
SkMatrix::I(),
ComputeSurfaceProps(can_use_lcd_text),
- strike_server) {
+ strike_server,
+ MakeCanvasSettings(context_supports_distance_field_text,
+ max_texture_size,
+ max_texture_bytes)) {
DCHECK(serialize_cb_);
canvas_ = SkCreateColorSpaceXformCanvas(&text_blob_canvas_,
sk_ref_sp<SkColorSpace>(color_space));
@@ -86,9 +106,7 @@ void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer,
// matrix, as they are only used for serializing the preamble and the initial
// save / final restore. SerializeBuffer will create its own SerializeOptions
// and PlaybackParams based on the post-preamble canvas.
- PaintOp::SerializeOptions options(
- image_provider_, transfer_cache_, canvas_.get(), strike_server_,
- color_space_, can_use_lcd_text_, canvas_->getTotalMatrix());
+ PaintOp::SerializeOptions options = MakeSerializeOptions();
PlaybackParams params = MakeParams(canvas_.get());
Save(options, params);
@@ -110,9 +128,7 @@ void PaintOpBufferSerializer::Serialize(
const SkMatrix& post_matrix_for_analysis) {
DCHECK(canvas_->getTotalMatrix().isIdentity());
- PaintOp::SerializeOptions options(
- image_provider_, transfer_cache_, canvas_.get(), strike_server_,
- color_space_, can_use_lcd_text_, canvas_->getTotalMatrix());
+ PaintOp::SerializeOptions options = MakeSerializeOptions();
PlaybackParams params = MakeParams(canvas_.get());
// TODO(khushalsagar): remove this clip rect if it's not needed.
@@ -131,6 +147,72 @@ void PaintOpBufferSerializer::Serialize(
SerializeBuffer(buffer, nullptr);
}
+// This function needs to have the exact same behavior as
+// RasterSource::ClearForOpaqueRaster.
+void PaintOpBufferSerializer::ClearForOpaqueRaster(
+ const Preamble& preamble,
+ const PaintOp::SerializeOptions& options,
+ const PlaybackParams& params) {
+ // Clear opaque raster sources. Opaque rasters sources guarantee that all
+ // pixels inside the opaque region are painted. However, due to scaling
+ // it's possible that the last row and column might include pixels that
+ // are not painted. Because this raster source is required to be opaque,
+ // we may need to do extra clearing outside of the clip. This needs to
+ // be done for both full and partial raster.
+
+ // The last texel of this content is not guaranteed to be fully opaque, so
+ // inset by one to generate the fully opaque coverage rect. This rect is
+ // in device space.
+ SkIRect coverage_device_rect = SkIRect::MakeWH(
+ preamble.content_size.width() - preamble.full_raster_rect.x() - 1,
+ preamble.content_size.height() - preamble.full_raster_rect.y() - 1);
+
+ // If not fully covered, we need to clear one texel inside the coverage
+ // rect (because of blending during raster) and one texel outside the canvas
+ // bitmap rect (because of bilinear filtering during draw). See comments
+ // in RasterSource.
+ SkIRect device_column = SkIRect::MakeXYWH(coverage_device_rect.right(), 0, 2,
+ coverage_device_rect.bottom());
+ // row includes the corner, column excludes it.
+ SkIRect device_row = SkIRect::MakeXYWH(0, coverage_device_rect.bottom(),
+ coverage_device_rect.right() + 2, 2);
+
+ bool right_edge =
+ preamble.content_size.width() == preamble.playback_rect.right();
+ bool bottom_edge =
+ preamble.content_size.height() == preamble.playback_rect.bottom();
+
+ // If the playback rect is touching either edge of the content rect
+ // extend it by one pixel to include the extra texel outside the canvas
+ // bitmap rect that was added to device column and row above.
+ SkIRect playback_device_rect = SkIRect::MakeXYWH(
+ preamble.playback_rect.x() - preamble.full_raster_rect.x(),
+ preamble.playback_rect.y() - preamble.full_raster_rect.y(),
+ preamble.playback_rect.width() + (right_edge ? 1 : 0),
+ preamble.playback_rect.height() + (bottom_edge ? 1 : 0));
+
+ // Intersect the device column and row with the playback rect and only
+ // clear inside of that rect if needed.
+ if (device_column.intersect(playback_device_rect)) {
+ Save(options, params);
+ ClipRectOp clip_op(SkRect::MakeFromIRect(device_column),
+ SkClipOp::kIntersect, false);
+ SerializeOp(&clip_op, options, params);
+ DrawColorOp clear_op(preamble.background_color, SkBlendMode::kSrc);
+ SerializeOp(&clear_op, options, params);
+ RestoreToCount(1, options, params);
+ }
+ if (device_row.intersect(playback_device_rect)) {
+ Save(options, params);
+ ClipRectOp clip_op(SkRect::MakeFromIRect(device_row), SkClipOp::kIntersect,
+ false);
+ SerializeOp(&clip_op, options, params);
+ DrawColorOp clear_op(preamble.background_color, SkBlendMode::kSrc);
+ SerializeOp(&clear_op, options, params);
+ RestoreToCount(1, options, params);
+ }
+}
+
void PaintOpBufferSerializer::SerializePreamble(
const Preamble& preamble,
const PaintOp::SerializeOptions& options,
@@ -139,58 +221,17 @@ void PaintOpBufferSerializer::SerializePreamble(
<< "full: " << preamble.full_raster_rect.ToString()
<< ", playback: " << preamble.playback_rect.ToString();
- // Should full clears be clipped?
bool is_partial_raster = preamble.full_raster_rect != preamble.playback_rect;
-
- // If rastering the entire tile, clear pre-clip. This is so that any
- // external texels outside of the playback rect also get cleared. There's
- // not enough information at this point to know if this texture is being
- // reused from another tile, so the external texels could have been
- // cleared to some wrong value.
- if (preamble.requires_clear && !is_partial_raster) {
- // If the tile is transparent, then just clear the whole thing.
+ if (!preamble.requires_clear) {
+ ClearForOpaqueRaster(preamble, options, params);
+ } else if (!is_partial_raster) {
+ // If rastering the entire tile, clear to transparent pre-clip. This is so
+ // that any external texels outside of the playback rect also get cleared.
+ // There's not enough information at this point to know if this texture is
+ // being reused from another tile, so the external texels could have been
+ // cleared to some wrong value.
DrawColorOp clear(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
SerializeOp(&clear, options, params);
- } else if (!is_partial_raster) {
- // The last texel of this content is not guaranteed to be fully opaque, so
- // inset by one to generate the fully opaque coverage rect . This rect is
- // in device space.
- SkIRect coverage_device_rect = SkIRect::MakeWH(
- preamble.content_size.width() - preamble.full_raster_rect.x() - 1,
- preamble.content_size.height() - preamble.full_raster_rect.y() - 1);
-
- SkIRect playback_device_rect = gfx::RectToSkIRect(preamble.playback_rect);
- playback_device_rect.fLeft -= preamble.full_raster_rect.x();
- playback_device_rect.fTop -= preamble.full_raster_rect.y();
-
- // If not fully covered, we need to clear one texel inside the coverage rect
- // (because of blending during raster) and one texel outside the full raster
- // rect (because of bilinear filtering during draw). See comments in
- // RasterSource.
- SkIRect device_column = SkIRect::MakeXYWH(coverage_device_rect.right(), 0,
- 2, coverage_device_rect.bottom());
- // row includes the corner, column excludes it.
- SkIRect device_row = SkIRect::MakeXYWH(0, coverage_device_rect.bottom(),
- coverage_device_rect.right() + 2, 2);
- // Only bother clearing if we need to.
- if (SkIRect::Intersects(device_column, playback_device_rect)) {
- Save(options, params);
- ClipRectOp clip_op(SkRect::MakeFromIRect(device_column),
- SkClipOp::kIntersect, false);
- SerializeOp(&clip_op, options, params);
- DrawColorOp clear_op(preamble.background_color, SkBlendMode::kSrc);
- SerializeOp(&clear_op, options, params);
- RestoreToCount(1, options, params);
- }
- if (SkIRect::Intersects(device_row, playback_device_rect)) {
- Save(options, params);
- ClipRectOp clip_op(SkRect::MakeFromIRect(device_row),
- SkClipOp::kIntersect, false);
- SerializeOp(&clip_op, options, params);
- DrawColorOp clear_op(preamble.background_color, SkBlendMode::kSrc);
- SerializeOp(&clear_op, options, params);
- RestoreToCount(1, options, params);
- }
}
if (!preamble.full_raster_rect.OffsetFromOrigin().IsZero()) {
@@ -230,9 +271,7 @@ void PaintOpBufferSerializer::SerializeBuffer(
const PaintOpBuffer* buffer,
const std::vector<size_t>* offsets) {
DCHECK(buffer);
- PaintOp::SerializeOptions options(
- image_provider_, transfer_cache_, canvas_.get(), strike_server_,
- color_space_, can_use_lcd_text_, canvas_->getTotalMatrix());
+ PaintOp::SerializeOptions options = MakeSerializeOptions();
PlaybackParams params = MakeParams(canvas_.get());
for (PaintOpBuffer::PlaybackFoldingIterator iter(buffer, offsets); iter;
@@ -301,6 +340,16 @@ bool PaintOpBufferSerializer::SerializeOp(
DCHECK_GE(bytes, 4u);
DCHECK_EQ(bytes % PaintOpBuffer::PaintOpAlign, 0u);
+ // Only 2 types of ops need to played on the analysis canvas.
+ // 1) Non-draw ops which affect the transform/clip state on the canvas, since
+ // we need the correct ctm at which text and images will be rasterized, and
+ // the clip rect so we can skip sending data for ops which will not be
+ // rasterized.
+ // 2) DrawTextBlob ops since they need to be analyzed by the cache diff canvas
+ // to serialize/lock the requisite glyphs for this op.
+ if (op->IsDrawOp() && op->GetType() != PaintOpType::DrawTextBlob)
+ return true;
+
if (op->IsPaintOpWithFlags() && options.flags_to_serialize) {
static_cast<const PaintOpWithFlags*>(op)->RasterWithFlags(
canvas_.get(), options.flags_to_serialize, params);
@@ -327,6 +376,13 @@ void PaintOpBufferSerializer::RestoreToCount(
}
}
+PaintOp::SerializeOptions PaintOpBufferSerializer::MakeSerializeOptions() {
+ return PaintOp::SerializeOptions(
+ image_provider_, transfer_cache_, canvas_.get(), strike_server_,
+ color_space_, can_use_lcd_text_, context_supports_distance_field_text_,
+ max_texture_size_, max_texture_bytes_, canvas_->getTotalMatrix());
+}
+
SimpleBufferSerializer::SimpleBufferSerializer(
void* memory,
size_t size,
@@ -334,7 +390,10 @@ SimpleBufferSerializer::SimpleBufferSerializer(
TransferCacheSerializeHelper* transfer_cache,
SkStrikeServer* strike_server,
SkColorSpace* color_space,
- bool can_use_lcd_text)
+ bool can_use_lcd_text,
+ bool context_supports_distance_field_text,
+ int max_texture_size,
+ size_t max_texture_bytes)
: PaintOpBufferSerializer(
base::Bind(&SimpleBufferSerializer::SerializeToMemory,
base::Unretained(this)),
@@ -342,7 +401,10 @@ SimpleBufferSerializer::SimpleBufferSerializer(
transfer_cache,
strike_server,
color_space,
- can_use_lcd_text),
+ can_use_lcd_text,
+ context_supports_distance_field_text,
+ max_texture_size,
+ max_texture_bytes),
memory_(memory),
total_(size) {}
diff --git a/chromium/cc/paint/paint_op_buffer_serializer.h b/chromium/cc/paint/paint_op_buffer_serializer.h
index 9f4f21cfa2d..1858e60221f 100644
--- a/chromium/cc/paint/paint_op_buffer_serializer.h
+++ b/chromium/cc/paint/paint_op_buffer_serializer.h
@@ -23,7 +23,10 @@ class CC_PAINT_EXPORT PaintOpBufferSerializer {
TransferCacheSerializeHelper* transfer_cache,
SkStrikeServer* strike_server,
SkColorSpace* color_space,
- bool can_use_lcd_text);
+ bool can_use_lcd_text,
+ bool context_supports_distance_field_text,
+ int max_texture_size,
+ size_t max_texture_bytes);
virtual ~PaintOpBufferSerializer();
struct Preamble {
@@ -91,6 +94,10 @@ class CC_PAINT_EXPORT PaintOpBufferSerializer {
void RestoreToCount(int count,
const PaintOp::SerializeOptions& options,
const PlaybackParams& params);
+ PaintOp::SerializeOptions MakeSerializeOptions();
+ void ClearForOpaqueRaster(const Preamble& preamble,
+ const PaintOp::SerializeOptions& options,
+ const PlaybackParams& params);
SerializeCallback serialize_cb_;
ImageProvider* image_provider_;
@@ -98,6 +105,9 @@ class CC_PAINT_EXPORT PaintOpBufferSerializer {
SkStrikeServer* strike_server_;
SkColorSpace* color_space_;
bool can_use_lcd_text_;
+ bool context_supports_distance_field_text_;
+ int max_texture_size_;
+ size_t max_texture_bytes_;
SkTextBlobCacheDiffCanvas text_blob_canvas_;
std::unique_ptr<SkCanvas> canvas_;
@@ -113,7 +123,10 @@ class CC_PAINT_EXPORT SimpleBufferSerializer : public PaintOpBufferSerializer {
TransferCacheSerializeHelper* transfer_cache,
SkStrikeServer* strike_server,
SkColorSpace* color_space,
- bool can_use_lcd_text);
+ bool can_use_lcd_text,
+ bool context_supports_distance_field_text,
+ int max_texture_size,
+ size_t max_texture_bytes);
~SimpleBufferSerializer() override;
size_t written() const { return written_; }
diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc
index b7b1d1e37fb..0b3aca669d6 100644
--- a/chromium/cc/paint/paint_op_buffer_unittest.cc
+++ b/chromium/cc/paint/paint_op_buffer_unittest.cc
@@ -1933,7 +1933,10 @@ TEST(PaintOpSerializationTest, CompleteBufferSerialization) {
options_provider.image_provider(),
options_provider.transfer_cache_helper(),
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
serializer.Serialize(&buffer, nullptr, preamble);
ASSERT_NE(serializer.written(), 0u);
@@ -2010,7 +2013,10 @@ TEST(PaintOpSerializationTest, Preamble) {
options_provider.image_provider(),
options_provider.transfer_cache_helper(),
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
serializer.Serialize(&buffer, nullptr, preamble);
ASSERT_NE(serializer.written(), 0u);
@@ -2110,7 +2116,10 @@ TEST(PaintOpSerializationTest, SerializesNestedRecords) {
options_provider.image_provider(),
options_provider.transfer_cache_helper(),
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
PaintOpBufferSerializer::Preamble preamble;
serializer.Serialize(&buffer, nullptr, preamble);
ASSERT_NE(serializer.written(), 0u);
@@ -2184,7 +2193,10 @@ TEST(PaintOpBufferTest, ClipsImagesDuringSerialization) {
options_provider.image_provider(),
options_provider.transfer_cache_helper(),
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
PaintOpBufferSerializer::Preamble preamble;
preamble.playback_rect = test_case.clip_rect;
preamble.full_raster_rect = gfx::Rect(0, 0, test_case.clip_rect.right(),
@@ -2247,7 +2259,10 @@ TEST(PaintOpBufferSerializationTest, AlphaFoldingDuringSerialization) {
options_provider.image_provider(),
options_provider.transfer_cache_helper(),
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
serializer.Serialize(&buffer, nullptr, preamble);
ASSERT_NE(serializer.written(), 0u);
@@ -2866,7 +2881,10 @@ TEST(PaintOpBufferTest, ReplacesImagesFromProviderOOP) {
options_provider.image_provider(),
options_provider.transfer_cache_helper(),
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
serializer.Serialize(&buffer);
ASSERT_NE(serializer.written(), 0u);
@@ -2975,13 +2993,8 @@ TEST_P(PaintFilterSerializationTest, Basic) {
buffer_size += PaintOpWriter::HeaderBytes();
memory.resize(buffer_size);
- PaintOp::SerializeOptions serialize_options(
- options_provider.image_provider(),
- options_provider.transfer_cache_helper(), nullptr,
- options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text(), SkMatrix::I());
- PaintOpWriter writer(memory.data(), memory.size(), serialize_options,
- GetParam());
+ PaintOpWriter writer(memory.data(), memory.size(),
+ options_provider.serialize_options(), GetParam());
writer.Write(filter.get());
ASSERT_GT(writer.size(), 0u) << PaintFilter::TypeToString(filter->type());
@@ -3017,7 +3030,10 @@ TEST(PaintOpBufferTest, PaintRecordShaderSerialization) {
options_provider.image_provider(),
options_provider.transfer_cache_helper(),
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
serializer.Serialize(&buffer);
ASSERT_TRUE(serializer.valid());
ASSERT_GT(serializer.written(), 0u);
@@ -3099,13 +3115,9 @@ TEST(PaintOpBufferTest, SecurityConstrainedImageSerialization) {
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
PaintOpBuffer::PaintOpAlign)));
TestOptionsProvider options_provider;
- PaintOp::SerializeOptions serialize_options(
- options_provider.image_provider(),
- options_provider.transfer_cache_helper(), nullptr,
- options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text(), SkMatrix::I());
PaintOpWriter writer(memory.get(), PaintOpBuffer::kInitialBufferSize,
- serialize_options, enable_security_constraints);
+ options_provider.serialize_options(),
+ enable_security_constraints);
writer.Write(filter.get());
sk_sp<PaintFilter> out_filter;
@@ -3118,6 +3130,39 @@ TEST(PaintOpBufferTest, SecurityConstrainedImageSerialization) {
EXPECT_TRUE(*filter == *out_filter);
}
+TEST(PaintOpBufferTest, DrawImageRectSerializeScaledImages) {
+ auto buffer = sk_make_sp<PaintOpBuffer>();
+ buffer->push<ScaleOp>(0.5f, 2.0f);
+
+ // scales: x dimension = x0.25, y dimension = x5
+ // translations here are arbitrary
+ SkRect src = SkRect::MakeXYWH(3, 4, 20, 6);
+ SkRect dst = SkRect::MakeXYWH(20, 38, 5, 30);
+ buffer->push<DrawImageRectOp>(
+ CreateDiscardablePaintImage(gfx::Size(32, 16)), src, dst, nullptr,
+ PaintCanvas::SrcRectConstraint::kStrict_SrcRectConstraint);
+
+ std::unique_ptr<char, base::AlignedFreeDeleter> memory(
+ static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
+ PaintOpBuffer::PaintOpAlign)));
+ TestOptionsProvider options_provider;
+ SimpleBufferSerializer serializer(
+ memory.get(), PaintOpBuffer::kInitialBufferSize,
+ options_provider.image_provider(),
+ options_provider.transfer_cache_helper(),
+ options_provider.strike_server(), options_provider.color_space(),
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
+ serializer.Serialize(buffer.get());
+
+ ASSERT_EQ(options_provider.decoded_images().size(), 1u);
+ auto scale = options_provider.decoded_images().at(0).scale();
+ EXPECT_EQ(scale.width(), 0.5f * 0.25f);
+ EXPECT_EQ(scale.height(), 2.0f * 5.0f);
+}
+
TEST(PaintOpBufferTest, RecordShadersSerializeScaledImages) {
auto record_buffer = sk_make_sp<PaintOpBuffer>();
record_buffer->push<DrawImageOp>(
@@ -3143,7 +3188,10 @@ TEST(PaintOpBufferTest, RecordShadersSerializeScaledImages) {
options_provider.image_provider(),
options_provider.transfer_cache_helper(),
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
serializer.Serialize(buffer.get());
ASSERT_EQ(options_provider.decoded_images().size(), 1u);
@@ -3180,7 +3228,10 @@ TEST(PaintOpBufferTest, RecordShadersCached) {
memory.get(), PaintOpBuffer::kInitialBufferSize,
options_provider.image_provider(), transfer_cache,
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
serializer.Serialize(buffer.get());
memory_written = serializer.written();
}
@@ -3203,7 +3254,10 @@ TEST(PaintOpBufferTest, RecordShadersCached) {
memory_scaled.get(), PaintOpBuffer::kInitialBufferSize,
options_provider.image_provider(), transfer_cache,
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
serializer.Serialize(buffer.get());
memory_scaled_written = serializer.written();
}
@@ -3302,9 +3356,14 @@ TEST(PaintOpBufferTest, RecordShadersCachedSize) {
SimpleBufferSerializer serializer(
memory.get(), PaintOpBuffer::kInitialBufferSize,
- options_provider.image_provider(), transfer_cache,
+ options_provider.image_provider(),
+ options_provider.transfer_cache_helper(),
options_provider.strike_server(), options_provider.color_space(),
- options_provider.can_use_lcd_text());
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
+ options_provider.context_supports_distance_field_text();
serializer.Serialize(buffer.get());
PaintOp::DeserializeOptions deserialize_options(
@@ -3338,4 +3397,34 @@ TEST(PaintOpBufferTest, TotalOpCount) {
EXPECT_EQ(3 * len + 2, record_buffer->total_op_count());
}
+TEST(PaintOpBufferTest, NullImages) {
+ PaintOpBuffer buffer;
+ buffer.push<DrawImageOp>(PaintImage(), 0.f, 0.f, nullptr);
+
+ std::unique_ptr<char, base::AlignedFreeDeleter> memory(
+ static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
+ PaintOpBuffer::PaintOpAlign)));
+ TestOptionsProvider options_provider;
+ SimpleBufferSerializer serializer(
+ memory.get(), PaintOpBuffer::kInitialBufferSize,
+ options_provider.image_provider(),
+ options_provider.transfer_cache_helper(),
+ options_provider.strike_server(), options_provider.color_space(),
+ options_provider.can_use_lcd_text(),
+ options_provider.context_supports_distance_field_text(),
+ options_provider.max_texture_size(),
+ options_provider.max_texture_bytes());
+ serializer.Serialize(&buffer);
+ ASSERT_TRUE(serializer.valid());
+ ASSERT_GT(serializer.written(), 0u);
+
+ auto deserialized_buffer =
+ PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
+ options_provider.deserialize_options());
+ ASSERT_TRUE(deserialized_buffer);
+ ASSERT_EQ(deserialized_buffer->size(), 1u);
+ ASSERT_EQ(deserialized_buffer->GetFirstOp()->GetType(),
+ PaintOpType::DrawImage);
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/paint_op_perftest.cc b/chromium/cc/paint/paint_op_perftest.cc
index dfefd8a8afa..336947163a8 100644
--- a/chromium/cc/paint/paint_op_perftest.cc
+++ b/chromium/cc/paint/paint_op_perftest.cc
@@ -53,7 +53,10 @@ class PaintOpPerfTest : public testing::Test {
test_options_provider.transfer_cache_helper(),
test_options_provider.strike_server(),
test_options_provider.color_space(),
- test_options_provider.can_use_lcd_text());
+ test_options_provider.can_use_lcd_text(),
+ test_options_provider.context_supports_distance_field_text(),
+ test_options_provider.max_texture_size(),
+ test_options_provider.max_texture_bytes());
serializer.Serialize(&buffer, nullptr, preamble);
bytes_written = serializer.written();
timer_.NextLap();
diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc
index e9c885c465d..ee3301f744f 100644
--- a/chromium/cc/paint/paint_op_reader.cc
+++ b/chromium/cc/paint/paint_op_reader.cc
@@ -153,23 +153,6 @@ void PaintOpReader::ReadData(size_t bytes, void* data) {
remaining_bytes_ -= bytes;
}
-void PaintOpReader::ReadArray(size_t count, SkPoint* array) {
- size_t bytes = count * sizeof(SkPoint);
- if (remaining_bytes_ < bytes)
- SetInvalid();
- // Overflow?
- if (count > static_cast<size_t>(~0) / sizeof(SkPoint))
- SetInvalid();
- if (!valid_)
- return;
- if (count == 0)
- return;
-
- memcpy(array, const_cast<const char*>(memory_), bytes);
- memory_ += bytes;
- remaining_bytes_ -= bytes;
-}
-
void PaintOpReader::ReadSize(size_t* size) {
ReadSimple(size);
}
@@ -320,6 +303,11 @@ void PaintOpReader::Read(PaintImage* image) {
if (!valid_)
return;
+ bool needs_mips;
+ ReadSimple(&needs_mips);
+ if (!valid_)
+ return;
+
// If we encountered a decode failure, we may write an invalid id for the
// image. In these cases, just return, leaving the image as nullptr.
if (transfer_cache_entry_id == kInvalidImageTransferCacheEntryId)
@@ -328,10 +316,16 @@ void PaintOpReader::Read(PaintImage* image) {
if (auto* entry =
options_.transfer_cache->GetEntryAs<ServiceImageTransferCacheEntry>(
transfer_cache_entry_id)) {
+ if (needs_mips)
+ entry->EnsureMips();
*image = PaintImageBuilder::WithDefault()
.set_id(PaintImage::GetNextId())
.set_image(entry->image(), PaintImage::kNonLazyStableId)
.TakePaintImage();
+ } else {
+ // If a transfer cache id exists, we must have a valid entry for it in the
+ // cache.
+ SetInvalid();
}
}
diff --git a/chromium/cc/paint/paint_op_reader.h b/chromium/cc/paint/paint_op_reader.h
index c8455fe8448..0188c8d54da 100644
--- a/chromium/cc/paint/paint_op_reader.h
+++ b/chromium/cc/paint/paint_op_reader.h
@@ -45,7 +45,6 @@ class CC_PAINT_EXPORT PaintOpReader {
size_t remaining_bytes() const { return remaining_bytes_; }
void ReadData(size_t bytes, void* data);
- void ReadArray(size_t count, SkPoint* array);
void ReadSize(size_t* size);
void Read(SkScalar* data);
diff --git a/chromium/cc/paint/paint_op_writer.cc b/chromium/cc/paint/paint_op_writer.cc
index 00338a6ba2f..9426b0dfdb4 100644
--- a/chromium/cc/paint/paint_op_writer.cc
+++ b/chromium/cc/paint/paint_op_writer.cc
@@ -206,10 +206,7 @@ void PaintOpWriter::Write(const PaintFlags& flags) {
void PaintOpWriter::Write(const DrawImage& draw_image,
SkSize* scale_adjustment) {
- // We never ask for subsets during serialization.
const PaintImage& paint_image = draw_image.paint_image();
- DCHECK_EQ(paint_image.width(), draw_image.src_rect().width());
- DCHECK_EQ(paint_image.height(), draw_image.src_rect().height());
// Empty image.
if (!draw_image.paint_image()) {
@@ -217,6 +214,10 @@ void PaintOpWriter::Write(const DrawImage& draw_image,
return;
}
+ // We never ask for subsets during serialization.
+ DCHECK_EQ(paint_image.width(), draw_image.src_rect().width());
+ DCHECK_EQ(paint_image.height(), draw_image.src_rect().height());
+
// Security constrained serialization inlines the image bitmap.
if (enable_security_constraints_) {
SkBitmap bm;
@@ -247,13 +248,21 @@ void PaintOpWriter::Write(const DrawImage& draw_image,
base::Optional<uint32_t> id = decoded_draw_image.transfer_cache_entry_id();
*scale_adjustment = decoded_draw_image.scale_adjustment();
// In the case of a decode failure, id may not be set. Send an invalid ID.
- WriteImage(id ? *id : kInvalidImageTransferCacheEntryId);
+ WriteImage(id.value_or(kInvalidImageTransferCacheEntryId),
+ decoded_draw_image.transfer_cache_entry_needs_mips());
}
-void PaintOpWriter::WriteImage(uint32_t transfer_cache_entry_id) {
+void PaintOpWriter::WriteImage(uint32_t transfer_cache_entry_id,
+ bool needs_mips) {
+ if (transfer_cache_entry_id == kInvalidImageTransferCacheEntryId) {
+ Write(static_cast<uint8_t>(PaintOp::SerializedImageType::kNoImage));
+ return;
+ }
+
Write(
static_cast<uint8_t>(PaintOp::SerializedImageType::kTransferCacheEntry));
Write(transfer_cache_entry_id);
+ Write(needs_mips);
}
void PaintOpWriter::Write(const sk_sp<SkData>& data) {
@@ -325,7 +334,8 @@ sk_sp<PaintShader> PaintOpWriter::TransformShaderIfNecessary(
const PaintShader* original,
SkFilterQuality quality,
uint32_t* paint_image_transfer_cache_entry_id,
- gfx::SizeF* paint_record_post_scale) {
+ gfx::SizeF* paint_record_post_scale,
+ bool* paint_image_needs_mips) {
DCHECK(!enable_security_constraints_);
const auto type = original->shader_type();
@@ -334,7 +344,7 @@ sk_sp<PaintShader> PaintOpWriter::TransformShaderIfNecessary(
if (type == PaintShader::Type::kImage) {
return original->CreateDecodedImage(ctm, quality, options_.image_provider,
paint_image_transfer_cache_entry_id,
- &quality);
+ &quality, paint_image_needs_mips);
}
if (type == PaintShader::Type::kPaintRecord) {
@@ -348,11 +358,12 @@ void PaintOpWriter::Write(const PaintShader* shader, SkFilterQuality quality) {
sk_sp<PaintShader> transformed_shader;
uint32_t paint_image_transfer_cache_id = kInvalidImageTransferCacheEntryId;
gfx::SizeF paint_record_post_scale(1.f, 1.f);
+ bool paint_image_needs_mips = false;
if (!enable_security_constraints_ && shader) {
transformed_shader = TransformShaderIfNecessary(
shader, quality, &paint_image_transfer_cache_id,
- &paint_record_post_scale);
+ &paint_record_post_scale, &paint_image_needs_mips);
shader = transformed_shader.get();
}
@@ -394,7 +405,7 @@ void PaintOpWriter::Write(const PaintShader* shader, SkFilterQuality quality) {
DCHECK_EQ(scale_adjustment.width(), 1.f);
DCHECK_EQ(scale_adjustment.height(), 1.f);
} else {
- WriteImage(paint_image_transfer_cache_id);
+ WriteImage(paint_image_transfer_cache_id, paint_image_needs_mips);
}
if (shader->record_) {
@@ -436,11 +447,6 @@ void PaintOpWriter::WriteData(size_t bytes, const void* input) {
remaining_bytes_ -= bytes;
}
-void PaintOpWriter::WriteArray(size_t count, const SkPoint* input) {
- size_t bytes = sizeof(SkPoint) * count;
- WriteData(bytes, input);
-}
-
void PaintOpWriter::AlignMemory(size_t alignment) {
// Due to the math below, alignment must be a power of two.
DCHECK_GT(alignment, 0u);
@@ -755,7 +761,8 @@ void PaintOpWriter::Write(const PaintRecord* record,
SimpleBufferSerializer serializer(
memory_, remaining_bytes_, options_.image_provider,
options_.transfer_cache, options_.strike_server, options_.color_space,
- options_.can_use_lcd_text);
+ options_.can_use_lcd_text, options_.context_supports_distance_field_text,
+ options_.max_texture_size, options_.max_texture_bytes);
serializer.Serialize(record, playback_rect, post_scale,
post_matrix_for_analysis);
diff --git a/chromium/cc/paint/paint_op_writer.h b/chromium/cc/paint/paint_op_writer.h
index ecca69ced59..25b38e949b6 100644
--- a/chromium/cc/paint/paint_op_writer.h
+++ b/chromium/cc/paint/paint_op_writer.h
@@ -40,8 +40,6 @@ class CC_PAINT_EXPORT PaintOpWriter {
// Write a sequence of arbitrary bytes.
void WriteData(size_t bytes, const void* input);
- void WriteArray(size_t count, const SkPoint* input);
-
size_t size() const { return valid_ ? size_ - remaining_bytes_ : 0u; }
void WriteSize(size_t size);
@@ -138,14 +136,15 @@ class CC_PAINT_EXPORT PaintOpWriter {
const gfx::SizeF& post_scale,
const SkMatrix& post_matrix_for_analysis);
void Write(const SkRegion& region);
- void WriteImage(uint32_t transfer_cache_entry_id);
+ void WriteImage(uint32_t transfer_cache_entry_id, bool needs_mips);
void EnsureBytes(size_t required_bytes);
sk_sp<PaintShader> TransformShaderIfNecessary(
const PaintShader* original,
SkFilterQuality quality,
uint32_t* paint_image_transfer_cache_entry_id,
- gfx::SizeF* paint_record_post_scale);
+ gfx::SizeF* paint_record_post_scale,
+ bool* paint_image_needs_mips);
char* memory_ = nullptr;
size_t size_ = 0u;
diff --git a/chromium/cc/paint/paint_shader.cc b/chromium/cc/paint/paint_shader.cc
index f06e539ddd9..c9b0c8d38d7 100644
--- a/chromium/cc/paint/paint_shader.cc
+++ b/chromium/cc/paint/paint_shader.cc
@@ -20,7 +20,9 @@ sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record,
const gfx::SizeF* raster_scale,
ImageProvider* image_provider) {
SkPictureRecorder recorder;
- SkCanvas* canvas = recorder.beginRecording(bounds);
+ SkCanvas* canvas =
+ recorder.beginRecording(SkRect::MakeWH(bounds.width(), bounds.height()));
+ canvas->translate(-bounds.fLeft, -bounds.fTop);
if (raster_scale)
canvas->scale(raster_scale->width(), raster_scale->height());
record->Playback(canvas, PlaybackParams(image_provider));
@@ -36,11 +38,13 @@ bool CompareMatrices(const SkMatrix& a,
SkSize scale;
SkMatrix a_without_scale;
SkMatrix b_without_scale;
- if (a.decomposeScale(&scale, &a_without_scale) !=
- b.decomposeScale(&scale, &b_without_scale)) {
+
+ const bool decomposes = a.decomposeScale(&scale, &a_without_scale);
+ if (decomposes != b.decomposeScale(&scale, &b_without_scale))
return false;
- }
+ if (!decomposes)
+ return true;
return PaintOp::AreSkMatricesEqual(a_without_scale, b_without_scale);
}
@@ -237,25 +241,26 @@ bool PaintShader::GetRasterizationTileRect(const SkMatrix& ctm,
SkScalarSqrt(matrix.getScaleY() * matrix.getScaleY() +
matrix.getSkewY() * matrix.getSkewY()));
}
- SkSize scaled_size =
- SkSize::Make(SkScalarAbs(scale.width() * tile_.width()),
- SkScalarAbs(scale.height() * tile_.height()));
+
+ SkScalar tile_area =
+ tile_.width() * tile_.height() * scale.width() * scale.height();
// Clamp the tile size to about 4M pixels.
// TODO(khushalsagar): We need to consider the max texture size as well.
static const SkScalar kMaxTileArea = 2048 * 2048;
- SkScalar tile_area = scaled_size.width() * scaled_size.height();
if (tile_area > kMaxTileArea) {
SkScalar clamp_scale = SkScalarSqrt(kMaxTileArea / tile_area);
- scaled_size.set(scaled_size.width() * clamp_scale,
- scaled_size.height() * clamp_scale);
+ scale.set(clamp_scale, clamp_scale);
}
- scaled_size = scaled_size.toCeil();
- if (scaled_size.isEmpty())
+ *tile_rect = SkRect::MakeXYWH(
+ tile_.fLeft * scale.width(), tile_.fTop * scale.height(),
+ SkScalarCeilToInt(SkScalarAbs(scale.width() * tile_.width())),
+ SkScalarCeilToInt(SkScalarAbs(scale.height() * tile_.height())));
+
+ if (tile_rect->isEmpty())
return false;
- *tile_rect = SkRect::MakeWH(scaled_size.width(), scaled_size.height());
return true;
}
@@ -305,7 +310,8 @@ sk_sp<PaintShader> PaintShader::CreateDecodedImage(
SkFilterQuality quality,
ImageProvider* image_provider,
uint32_t* transfer_cache_entry_id,
- SkFilterQuality* raster_quality) const {
+ SkFilterQuality* raster_quality,
+ bool* needs_mips) const {
DCHECK_EQ(shader_type_, Type::kImage);
if (!image_)
return nullptr;
@@ -348,6 +354,7 @@ sk_sp<PaintShader> PaintShader::CreateDecodedImage(
// want to do is cap the filter quality used, but Gpu and Sw cache have
// different behaviour. D:
*raster_quality = decoded_image.filter_quality();
+ *needs_mips = decoded_image.transfer_cache_entry_needs_mips();
return PaintShader::MakeImage(decoded_paint_image, tx_, ty_, &final_matrix);
}
diff --git a/chromium/cc/paint/paint_shader.h b/chromium/cc/paint/paint_shader.h
index 6c2e963fb40..b0444bbfd96 100644
--- a/chromium/cc/paint/paint_shader.h
+++ b/chromium/cc/paint/paint_shader.h
@@ -159,6 +159,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
private:
friend class PaintFlags;
+ friend class PaintOpHelper;
friend class PaintOpReader;
friend class PaintOpSerializationTestUtils;
friend class PaintOpWriter;
@@ -192,7 +193,8 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
SkFilterQuality requested_quality,
ImageProvider* image_provider,
uint32_t* transfer_cache_entry_id,
- SkFilterQuality* raster_quality) const;
+ SkFilterQuality* raster_quality,
+ bool* needs_mips) const;
void SetColorsAndPositions(const SkColor* colors,
const SkScalar* positions,
diff --git a/chromium/cc/paint/paint_typeface.cc b/chromium/cc/paint/paint_typeface.cc
index 2595d84e03a..d6ee8c0bb04 100644
--- a/chromium/cc/paint/paint_typeface.cc
+++ b/chromium/cc/paint/paint_typeface.cc
@@ -4,8 +4,8 @@
#include "cc/paint/paint_typeface.h"
#include "build/build_config.h"
+#include "third_party/skia/include/core/SkFontMgr.h"
#include "third_party/skia/include/ports/SkFontConfigInterface.h"
-#include "third_party/skia/include/ports/SkFontMgr.h"
namespace cc {
diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc
index c601f19296d..2250b26e803 100644
--- a/chromium/cc/paint/record_paint_canvas.cc
+++ b/chromium/cc/paint/record_paint_canvas.cc
@@ -263,23 +263,6 @@ void RecordPaintCanvas::drawImageRect(const PaintImage& image,
list_->push<DrawImageRectOp>(image, src, dst, flags, constraint);
}
-void RecordPaintCanvas::drawBitmap(const SkBitmap& bitmap,
- SkScalar left,
- SkScalar top,
- const PaintFlags* flags) {
- // TODO(enne): Move into base class?
- if (bitmap.drawsNothing())
- return;
- // TODO(khushalsagar): Remove this and have callers use PaintImages holding
- // bitmap-backed images, since they can maintain the PaintImage::Id.
- drawImage(PaintImageBuilder::WithDefault()
- .set_id(PaintImage::GetNextId())
- .set_image(SkImage::MakeFromBitmap(bitmap),
- PaintImage::GetNextContentId())
- .TakePaintImage(),
- left, top, flags);
-}
-
void RecordPaintCanvas::drawTextBlob(scoped_refptr<PaintTextBlob> blob,
SkScalar x,
SkScalar y,
diff --git a/chromium/cc/paint/record_paint_canvas.h b/chromium/cc/paint/record_paint_canvas.h
index 5eae2c88916..fb39721603f 100644
--- a/chromium/cc/paint/record_paint_canvas.h
+++ b/chromium/cc/paint/record_paint_canvas.h
@@ -84,10 +84,6 @@ class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas {
const SkRect& dst,
const PaintFlags* flags,
SrcRectConstraint constraint) override;
- void drawBitmap(const SkBitmap& bitmap,
- SkScalar left,
- SkScalar top,
- const PaintFlags* flags) override;
void drawTextBlob(scoped_refptr<PaintTextBlob> blob,
SkScalar x,
@@ -109,7 +105,6 @@ class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas {
using PaintCanvas::clipRect;
using PaintCanvas::clipRRect;
using PaintCanvas::clipPath;
- using PaintCanvas::drawBitmap;
using PaintCanvas::drawColor;
using PaintCanvas::drawImage;
using PaintCanvas::drawPicture;
diff --git a/chromium/cc/paint/scoped_raster_flags.cc b/chromium/cc/paint/scoped_raster_flags.cc
index cee4465a8c6..960e6b3acb2 100644
--- a/chromium/cc/paint/scoped_raster_flags.cc
+++ b/chromium/cc/paint/scoped_raster_flags.cc
@@ -47,10 +47,13 @@ void ScopedRasterFlags::DecodeImageShader(const SkMatrix& ctm) {
uint32_t transfer_cache_entry_id = kInvalidImageTransferCacheEntryId;
SkFilterQuality raster_quality = flags()->getFilterQuality();
+ bool transfer_cache_entry_needs_mips = false;
auto decoded_shader = flags()->getShader()->CreateDecodedImage(
ctm, flags()->getFilterQuality(), &*decode_stashing_image_provider_,
- &transfer_cache_entry_id, &raster_quality);
+ &transfer_cache_entry_id, &raster_quality,
+ &transfer_cache_entry_needs_mips);
DCHECK_EQ(transfer_cache_entry_id, kInvalidImageTransferCacheEntryId);
+ DCHECK_EQ(transfer_cache_entry_needs_mips, false);
if (!decoded_shader) {
decode_failed_ = true;
diff --git a/chromium/cc/paint/skia_paint_canvas.cc b/chromium/cc/paint/skia_paint_canvas.cc
index b5963ca9d05..875b82f782e 100644
--- a/chromium/cc/paint/skia_paint_canvas.cc
+++ b/chromium/cc/paint/skia_paint_canvas.cc
@@ -300,23 +300,6 @@ void SkiaPaintCanvas::drawImageRect(const PaintImage& image,
FlushAfterDrawIfNeeded();
}
-void SkiaPaintCanvas::drawBitmap(const SkBitmap& bitmap,
- SkScalar left,
- SkScalar top,
- const PaintFlags* flags) {
- if (flags) {
- ScopedRasterFlags raster_flags(flags, image_provider_,
- canvas_->getTotalMatrix(), 255u);
- if (!raster_flags.flags())
- return;
- SkPaint paint = raster_flags.flags()->ToSkPaint();
- canvas_->drawBitmap(bitmap, left, top, &paint);
- } else {
- canvas_->drawBitmap(bitmap, left, top, nullptr);
- }
- FlushAfterDrawIfNeeded();
-}
-
void SkiaPaintCanvas::drawTextBlob(scoped_refptr<PaintTextBlob> blob,
SkScalar x,
SkScalar y,
diff --git a/chromium/cc/paint/skia_paint_canvas.h b/chromium/cc/paint/skia_paint_canvas.h
index c9e1936733e..8a589743f46 100644
--- a/chromium/cc/paint/skia_paint_canvas.h
+++ b/chromium/cc/paint/skia_paint_canvas.h
@@ -106,10 +106,6 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
const SkRect& dst,
const PaintFlags* flags,
SrcRectConstraint constraint) override;
- void drawBitmap(const SkBitmap& bitmap,
- SkScalar left,
- SkScalar top,
- const PaintFlags* flags) override;
void drawTextBlob(scoped_refptr<PaintTextBlob> blob,
SkScalar x,
@@ -130,7 +126,6 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
using PaintCanvas::clipRect;
using PaintCanvas::clipRRect;
using PaintCanvas::clipPath;
- using PaintCanvas::drawBitmap;
using PaintCanvas::drawColor;
using PaintCanvas::drawImage;
using PaintCanvas::drawPicture;
diff --git a/chromium/cc/paint/solid_color_analyzer_unittest.cc b/chromium/cc/paint/solid_color_analyzer_unittest.cc
index 4c40b602aed..939e517af61 100644
--- a/chromium/cc/paint/solid_color_analyzer_unittest.cc
+++ b/chromium/cc/paint/solid_color_analyzer_unittest.cc
@@ -114,14 +114,6 @@ TEST_F(SolidColorAnalyzerTest, DrawOval) {
EXPECT_FALSE(IsSolidColor());
}
-TEST_F(SolidColorAnalyzerTest, DrawBitmap) {
- Initialize();
- SkBitmap bitmap;
- bitmap.allocN32Pixels(16, 16);
- canvas()->drawBitmap(bitmap, 0, 0, nullptr);
- EXPECT_FALSE(IsSolidColor());
-}
-
TEST_F(SolidColorAnalyzerTest, DrawRect) {
Initialize();
PaintFlags flags;
diff --git a/chromium/cc/paint/transfer_cache_unittest.cc b/chromium/cc/paint/transfer_cache_unittest.cc
index d8fb589c35d..9deaf3d0825 100644
--- a/chromium/cc/paint/transfer_cache_unittest.cc
+++ b/chromium/cc/paint/transfer_cache_unittest.cc
@@ -49,8 +49,7 @@ class TransferCacheTest : public testing::Test {
auto result = context_->Initialize(
/*service=*/nullptr, attribs, gpu::SharedMemoryLimits(),
&gpu_memory_buffer_manager_, &image_factory_,
- /*gpu_channel_manager_delegate=*/nullptr,
- base::ThreadTaskRunnerHandle::Get());
+ /*gpu_channel_manager_delegate=*/nullptr);
ASSERT_EQ(result, gpu::ContextResult::kSuccess);
ASSERT_TRUE(context_->GetCapabilities().supports_oop_raster);
@@ -62,6 +61,8 @@ class TransferCacheTest : public testing::Test {
return context_->GetTransferCacheForTest();
}
+ int decoder_id() { return context_->GetRasterDecoderIdForTest(); }
+
gpu::raster::RasterInterface* ri() { return context_->GetImplementation(); }
gpu::ContextSupport* ContextSupport() {
@@ -99,7 +100,9 @@ TEST_F(TransferCacheTest, Basic) {
ri()->Finish();
// Validate service-side state.
- EXPECT_NE(nullptr, service_cache->GetEntry(entry.Type(), entry.Id()));
+ EXPECT_NE(nullptr,
+ service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
+ decoder_id(), entry.Type(), entry.Id())));
// Unlock on client side and flush to service.
context_support->UnlockTransferCacheEntries(
@@ -114,7 +117,9 @@ TEST_F(TransferCacheTest, Basic) {
// Delete on client side, flush, and validate that deletion reaches service.
context_support->DeleteTransferCacheEntry(entry.UnsafeType(), entry.Id());
ri()->Finish();
- EXPECT_EQ(nullptr, service_cache->GetEntry(entry.Type(), entry.Id()));
+ EXPECT_EQ(nullptr,
+ service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
+ decoder_id(), entry.Type(), entry.Id())));
}
TEST_F(TransferCacheTest, Eviction) {
@@ -127,7 +132,9 @@ TEST_F(TransferCacheTest, Eviction) {
ri()->Finish();
// Validate service-side state.
- EXPECT_NE(nullptr, service_cache->GetEntry(entry.Type(), entry.Id()));
+ EXPECT_NE(nullptr,
+ service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
+ decoder_id(), entry.Type(), entry.Id())));
// Unlock on client side and flush to service.
context_support->UnlockTransferCacheEntries(
@@ -136,7 +143,9 @@ TEST_F(TransferCacheTest, Eviction) {
// Evict on the service side.
service_cache->SetCacheSizeLimitForTesting(0);
- EXPECT_EQ(nullptr, service_cache->GetEntry(entry.Type(), entry.Id()));
+ EXPECT_EQ(nullptr,
+ service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
+ decoder_id(), entry.Type(), entry.Id())));
// Try to re-lock on the client side. This should fail.
EXPECT_FALSE(context_support->ThreadsafeLockTransferCacheEntry(
@@ -160,7 +169,8 @@ TEST_F(TransferCacheTest, RawMemoryTransfer) {
// Validate service-side data matches.
ServiceTransferCacheEntry* service_entry =
- service_cache->GetEntry(client_entry.Type(), client_entry.Id());
+ service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
+ decoder_id(), client_entry.Type(), client_entry.Id()));
EXPECT_EQ(service_entry->Type(), client_entry.Type());
const std::vector<uint8_t> service_data =
static_cast<ServiceRawMemoryTransferCacheEntry*>(service_entry)->data();
@@ -185,13 +195,14 @@ TEST_F(TransferCacheTest, ImageMemoryTransfer) {
SkPixmap pixmap(info, data.data(), info.minRowBytes());
// Add the entry to the transfer cache
- ClientImageTransferCacheEntry client_entry(&pixmap, nullptr);
+ ClientImageTransferCacheEntry client_entry(&pixmap, nullptr, false);
CreateEntry(client_entry);
ri()->Finish();
// Validate service-side data matches.
ServiceTransferCacheEntry* service_entry =
- service_cache->GetEntry(client_entry.Type(), client_entry.Id());
+ service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
+ decoder_id(), client_entry.Type(), client_entry.Id()));
EXPECT_EQ(service_entry->Type(), client_entry.Type());
sk_sp<SkImage> service_image =
static_cast<ServiceImageTransferCacheEntry*>(service_entry)->image();
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc
index f449095504c..dd6a8470529 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.cc
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc
@@ -17,7 +17,7 @@
#include "cc/paint/paint_recorder.h"
#include "cc/raster/raster_source.h"
#include "cc/raster/scoped_gpu_raster.h"
-#include "cc/resources/layer_tree_resource_provider.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "components/viz/common/gpu/texture_allocation.h"
@@ -71,7 +71,7 @@ class ScopedSkSurfaceForUnpremultiplyAndDither {
SkImageInfo n32Info = SkImageInfo::MakeN32Premul(
intermediate_size.width(), intermediate_size.height());
SkSurfaceProps surface_props =
- LayerTreeResourceProvider::ScopedSkSurface::ComputeSurfaceProps(
+ viz::ClientResourceProvider::ScopedSkSurface::ComputeSurfaceProps(
can_use_lcd_text);
surface_ = SkSurface::MakeRenderTarget(
context_provider->GrContext(), SkBudgeted::kNo, n32Info,
@@ -138,11 +138,11 @@ static void RasterizeSourceOOP(
// TODO(enne): Use the |texture_target|? GpuMemoryBuffer backed textures don't
// use GL_TEXTURE_2D.
- ri->BeginRasterCHROMIUM(texture_id, raster_source->background_color(),
- msaa_sample_count, playback_settings.use_lcd_text,
+ ri->BeginRasterCHROMIUM(raster_source->background_color(), msaa_sample_count,
+ playback_settings.use_lcd_text,
viz::ResourceFormatToClosestSkColorType(
/*gpu_compositing=*/true, resource_format),
- playback_settings.raster_color_space);
+ playback_settings.raster_color_space, mailbox.name);
float recording_to_raster_scale =
transform.scale() / raster_source->recording_scale_factor();
gfx::Size content_size = raster_source->GetContentSize(transform.scale());
@@ -212,7 +212,7 @@ static void RasterizeSource(
{
ScopedGrContextAccess gr_context_access(context_provider);
- base::Optional<LayerTreeResourceProvider::ScopedSkSurface> scoped_surface;
+ base::Optional<viz::ClientResourceProvider::ScopedSkSurface> scoped_surface;
base::Optional<ScopedSkSurfaceForUnpremultiplyAndDither>
scoped_dither_surface;
SkSurface* surface;
@@ -379,13 +379,12 @@ std::unique_ptr<RasterBuffer> GpuRasterBufferProvider::AcquireBufferForRaster(
backing->texture_id = alloc.texture_id;
backing->texture_target = alloc.texture_target;
backing->overlay_candidate = alloc.overlay_candidate;
- backing->mailbox = gpu::Mailbox::Generate();
gl->ProduceTextureDirectCHROMIUM(backing->texture_id,
backing->mailbox.name);
// Save a sync token in the backing so that we always wait on it even if
// this task is cancelled between being scheduled and running.
backing->returned_sync_token =
- LayerTreeResourceProvider::GenerateSyncTokenHelper(gl);
+ viz::ClientResourceProvider::GenerateSyncTokenHelper(gl);
resource.set_gpu_backing(std::move(backing));
}
@@ -528,7 +527,7 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThread(
}
// Generate sync token for cross context synchronization.
- return LayerTreeResourceProvider::GenerateSyncTokenHelper(ri);
+ return viz::ClientResourceProvider::GenerateSyncTokenHelper(ri);
}
bool GpuRasterBufferProvider::ShouldUnpremultiplyAndDitherResource(
diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.cc b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
index 90f94f65055..c978c85654c 100644
--- a/chromium/cc/raster/one_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
@@ -173,13 +173,12 @@ OneCopyRasterBufferProvider::AcquireBufferForRaster(
backing->texture_id = alloc.texture_id;
backing->texture_target = alloc.texture_target;
backing->overlay_candidate = alloc.overlay_candidate;
- backing->mailbox = gpu::Mailbox::Generate();
gl->ProduceTextureDirectCHROMIUM(backing->texture_id,
backing->mailbox.name);
// Save a sync token in the backing so that we always wait on it even if
// this task is cancelled between being scheduled and running.
backing->returned_sync_token =
- LayerTreeResourceProvider::GenerateSyncTokenHelper(gl);
+ viz::ClientResourceProvider::GenerateSyncTokenHelper(gl);
resource.set_gpu_backing(std::move(backing));
}
@@ -487,7 +486,7 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread(
// Generate sync token on the worker context that will be sent to and waited
// for by the display compositor before using the content generated here.
- return LayerTreeResourceProvider::GenerateSyncTokenHelper(ri);
+ return viz::ClientResourceProvider::GenerateSyncTokenHelper(ri);
}
gfx::BufferUsage OneCopyRasterBufferProvider::StagingBufferUsage() const {
diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.h b/chromium/cc/raster/one_copy_raster_buffer_provider.h
index 3c823596cba..4f4a1e2fb50 100644
--- a/chromium/cc/raster/one_copy_raster_buffer_provider.h
+++ b/chromium/cc/raster/one_copy_raster_buffer_provider.h
@@ -11,7 +11,7 @@
#include "base/sequenced_task_runner.h"
#include "cc/raster/raster_buffer_provider.h"
#include "cc/raster/staging_buffer_pool.h"
-#include "cc/resources/layer_tree_resource_provider.h"
+#include "components/viz/client/client_resource_provider.h"
#include "gpu/command_buffer/common/sync_token.h"
namespace gpu {
diff --git a/chromium/cc/raster/playback_image_provider.cc b/chromium/cc/raster/playback_image_provider.cc
index 75d8ddf0608..a539f0b1fe4 100644
--- a/chromium/cc/raster/playback_image_provider.cc
+++ b/chromium/cc/raster/playback_image_provider.cc
@@ -47,12 +47,6 @@ PlaybackImageProvider::GetDecodedDrawImage(const DrawImage& draw_image) {
return ScopedDecodedDrawImage();
}
- if (paint_image.GetSkImage()->isTextureBacked()) {
- return ScopedDecodedDrawImage(DecodedDrawImage(
- paint_image.GetSkImage(), SkSize::Make(0, 0), SkSize::Make(1.f, 1.f),
- draw_image.filter_quality(), true /* is_budgeted */));
- }
-
const auto& it =
settings_->image_to_current_frame_index.find(paint_image.stable_id());
size_t frame_index = it == settings_->image_to_current_frame_index.end()
@@ -60,8 +54,13 @@ PlaybackImageProvider::GetDecodedDrawImage(const DrawImage& draw_image) {
: it->second;
DrawImage adjusted_image(draw_image, 1.f, frame_index, target_color_space_);
- auto decoded_draw_image = cache_->GetDecodedImageForDraw(adjusted_image);
+ if (!cache_->UseCacheForDrawImage(adjusted_image)) {
+ return ScopedDecodedDrawImage(DecodedDrawImage(
+ paint_image.GetSkImage(), SkSize::Make(0, 0), SkSize::Make(1.f, 1.f),
+ draw_image.filter_quality(), true /* is_budgeted */));
+ }
+ auto decoded_draw_image = cache_->GetDecodedImageForDraw(adjusted_image);
return ScopedDecodedDrawImage(
decoded_draw_image,
base::BindOnce(&UnrefImageFromCache, std::move(adjusted_image), cache_,
diff --git a/chromium/cc/raster/playback_image_provider_unittest.cc b/chromium/cc/raster/playback_image_provider_unittest.cc
index 40036e87032..dd4f6a4a9e8 100644
--- a/chromium/cc/raster/playback_image_provider_unittest.cc
+++ b/chromium/cc/raster/playback_image_provider_unittest.cc
@@ -46,6 +46,13 @@ class MockDecodeCache : public StubDecodeCache {
EXPECT_GE(refed_image_count_, 0);
}
+ bool UseCacheForDrawImage(const DrawImage& image) const override {
+ return use_cache_for_draw_image_;
+ }
+
+ void set_use_cache_for_draw_image(bool use) {
+ use_cache_for_draw_image_ = use;
+ }
int refed_image_count() const { return refed_image_count_; }
int images_decoded() const { return images_decoded_; }
const DrawImage& last_image() { return last_image_; }
@@ -53,6 +60,7 @@ class MockDecodeCache : public StubDecodeCache {
private:
int refed_image_count_ = 0;
int images_decoded_ = 0;
+ bool use_cache_for_draw_image_ = true;
DrawImage last_image_;
};
@@ -163,19 +171,9 @@ TEST(PlaybackImageProviderTest, BitmapImages) {
EXPECT_EQ(cache.refed_image_count(), 0);
}
-TEST(PlaybackImageProviderTest, TextureImages) {
- // Texture images should never hit the ImageDecodeCache.
- sk_sp<const GrGLInterface> gl_interface(GrGLCreateNullInterface());
- auto context = GrContext::MakeGL(std::move(gl_interface));
- auto sk_texture_image = CreateBitmapImage(gfx::Size(10, 10))
- .GetSkImage()
- ->makeTextureImage(context.get(), nullptr);
- auto image = PaintImageBuilder::WithDefault()
- .set_id(PaintImage::GetNextId())
- .set_image(sk_texture_image, PaintImage::GetNextContentId())
- .TakePaintImage();
-
+TEST(PlaybackImageProviderTest, IgnoresImagesNotSupportedByCache) {
MockDecodeCache cache;
+ cache.set_use_cache_for_draw_image(false);
base::Optional<PlaybackImageProvider::Settings> settings;
settings.emplace();
PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
@@ -183,7 +181,8 @@ TEST(PlaybackImageProviderTest, TextureImages) {
{
SkIRect rect = SkIRect::MakeWH(10, 10);
SkMatrix matrix = SkMatrix::I();
- auto draw_image = DrawImage(image, rect, kMedium_SkFilterQuality, matrix);
+ auto draw_image = DrawImage(CreateBitmapImage(gfx::Size(10, 10)), rect,
+ kMedium_SkFilterQuality, matrix);
auto decode = provider.GetDecodedDrawImage(draw_image);
EXPECT_TRUE(decode);
EXPECT_EQ(cache.refed_image_count(), 0);
diff --git a/chromium/cc/raster/raster_buffer_provider.cc b/chromium/cc/raster/raster_buffer_provider.cc
index 873a432e0ef..57f2a6d01f3 100644
--- a/chromium/cc/raster/raster_buffer_provider.cc
+++ b/chromium/cc/raster/raster_buffer_provider.cc
@@ -38,6 +38,15 @@ bool IsSupportedPlaybackToMemoryFormat(viz::ResourceFormat format) {
case viz::LUMINANCE_F16:
case viz::RGBA_F16:
case viz::R16_EXT:
+ case viz::BGR_565:
+ case viz::RG_88:
+ case viz::RGBX_8888:
+ case viz::BGRX_8888:
+ case viz::RGBX_1010102:
+ case viz::BGRX_1010102:
+ case viz::YVU_420:
+ case viz::YUV_420_BIPLANAR:
+ case viz::UYVY_422:
return false;
}
NOTREACHED();
@@ -136,6 +145,15 @@ void RasterBufferProvider::PlaybackToMemory(
case viz::RED_8:
case viz::LUMINANCE_F16:
case viz::R16_EXT:
+ case viz::BGR_565:
+ case viz::RG_88:
+ case viz::RGBX_8888:
+ case viz::BGRX_8888:
+ case viz::RGBX_1010102:
+ case viz::BGRX_1010102:
+ case viz::YVU_420:
+ case viz::YUV_420_BIPLANAR:
+ case viz::UYVY_422:
NOTREACHED();
return;
}
diff --git a/chromium/cc/raster/raster_buffer_provider_perftest.cc b/chromium/cc/raster/raster_buffer_provider_perftest.cc
index a91d3bef29d..36db4d2c575 100644
--- a/chromium/cc/raster/raster_buffer_provider_perftest.cc
+++ b/chromium/cc/raster/raster_buffer_provider_perftest.cc
@@ -16,11 +16,10 @@
#include "cc/raster/raster_buffer_provider.h"
#include "cc/raster/synchronous_task_graph_runner.h"
#include "cc/raster/zero_copy_raster_buffer_provider.h"
-#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/resources/resource_pool.h"
#include "cc/test/fake_layer_tree_frame_sink.h"
-#include "cc/test/fake_resource_provider.h"
#include "cc/tiles/tile_task_manager.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/gpu/context_cache_controller.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/resources/platform_color.h"
@@ -331,7 +330,7 @@ class RasterBufferProviderPerfTestBase {
scoped_refptr<viz::ContextProvider> compositor_context_provider_;
scoped_refptr<viz::RasterContextProvider> worker_context_provider_;
std::unique_ptr<FakeLayerTreeFrameSink> layer_tree_frame_sink_;
- std::unique_ptr<LayerTreeResourceProvider> resource_provider_;
+ std::unique_ptr<viz::ClientResourceProvider> resource_provider_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
std::unique_ptr<ResourcePool> resource_pool_;
std::unique_ptr<SynchronousTaskGraphRunner> task_graph_runner_;
@@ -501,14 +500,12 @@ class RasterBufferProviderPerfTest
private:
void Create3dResourceProvider() {
- resource_provider_ = FakeResourceProvider::CreateLayerTreeResourceProvider(
- compositor_context_provider_.get());
+ resource_provider_ = std::make_unique<viz::ClientResourceProvider>(true);
}
void CreateSoftwareResourceProvider() {
layer_tree_frame_sink_ = FakeLayerTreeFrameSink::CreateSoftware();
- resource_provider_ =
- FakeResourceProvider::CreateLayerTreeResourceProvider(nullptr);
+ resource_provider_ = std::make_unique<viz::ClientResourceProvider>(true);
}
std::string TestModifierString() const {
@@ -571,8 +568,7 @@ class RasterBufferProviderCommonPerfTest
public:
// Overridden from testing::Test:
void SetUp() override {
- resource_provider_ = FakeResourceProvider::CreateLayerTreeResourceProvider(
- compositor_context_provider_.get());
+ resource_provider_ = std::make_unique<viz::ClientResourceProvider>(true);
resource_pool_ = std::make_unique<ResourcePool>(
resource_provider_.get(), compositor_context_provider_.get(),
task_runner_, ResourcePool::kDefaultExpirationDelay, false);
diff --git a/chromium/cc/raster/raster_buffer_provider_unittest.cc b/chromium/cc/raster/raster_buffer_provider_unittest.cc
index c50e739199c..b7de488d4a7 100644
--- a/chromium/cc/raster/raster_buffer_provider_unittest.cc
+++ b/chromium/cc/raster/raster_buffer_provider_unittest.cc
@@ -24,16 +24,14 @@
#include "cc/raster/one_copy_raster_buffer_provider.h"
#include "cc/raster/synchronous_task_graph_runner.h"
#include "cc/raster/zero_copy_raster_buffer_provider.h"
-#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/resources/resource_pool.h"
#include "cc/test/fake_layer_tree_frame_sink.h"
#include "cc/test/fake_raster_source.h"
-#include "cc/test/fake_resource_provider.h"
#include "cc/tiles/tile_task_manager.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/resources/platform_color.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gpu_memory_buffer_manager.h"
-#include "components/viz/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -298,14 +296,12 @@ class RasterBufferProviderTest
context_provider_->BindToCurrentThread();
worker_context_provider_ = viz::TestContextProvider::CreateWorker();
layer_tree_frame_sink_ = FakeLayerTreeFrameSink::Create3d();
- resource_provider_ = FakeResourceProvider::CreateLayerTreeResourceProvider(
- context_provider_.get());
+ resource_provider_ = std::make_unique<viz::ClientResourceProvider>(true);
}
void CreateSoftwareResourceProvider() {
layer_tree_frame_sink_ = FakeLayerTreeFrameSink::CreateSoftware();
- resource_provider_ =
- FakeResourceProvider::CreateLayerTreeResourceProvider(nullptr);
+ resource_provider_ = std::make_unique<viz::ClientResourceProvider>(true);
}
void OnTimeout() {
@@ -318,7 +314,7 @@ class RasterBufferProviderTest
scoped_refptr<viz::TestContextProvider> worker_context_provider_;
std::unique_ptr<ResourcePool> pool_;
std::unique_ptr<FakeLayerTreeFrameSink> layer_tree_frame_sink_;
- std::unique_ptr<LayerTreeResourceProvider> resource_provider_;
+ std::unique_ptr<viz::ClientResourceProvider> resource_provider_;
std::unique_ptr<TileTaskManager> tile_task_manager_;
std::unique_ptr<RasterBufferProvider> raster_buffer_provider_;
viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
@@ -349,8 +345,8 @@ TEST_P(RasterBufferProviderTest, FailedMapResource) {
if (GetParam() == RASTER_BUFFER_PROVIDER_TYPE_BITMAP)
return;
- viz::TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
- context3d->set_times_map_buffer_chromium_succeeds(0);
+ viz::TestGLES2Interface* gl = context_provider_->TestContextGL();
+ gl->set_times_map_buffer_chromium_succeeds(0);
AppendTask(0u);
ScheduleTasks();
@@ -478,9 +474,8 @@ TEST_P(RasterBufferProviderTest, WaitOnSyncTokenAfterReschedulingTask) {
{
viz::ContextProvider::ScopedContextLock context_lock(
worker_context_provider_.get());
- viz::TestWebGraphicsContext3D* context3d =
- worker_context_provider_->TestContext3d();
- EXPECT_TRUE(context3d->last_waited_sync_token().HasData());
+ viz::TestGLES2Interface* gl = worker_context_provider_->TestContextGL();
+ EXPECT_TRUE(gl->last_waited_sync_token().HasData());
}
lock.Release();
diff --git a/chromium/cc/raster/raster_source.cc b/chromium/cc/raster/raster_source.cc
index be224fe6d8e..be0cb4fbb3f 100644
--- a/chromium/cc/raster/raster_source.cc
+++ b/chromium/cc/raster/raster_source.cc
@@ -54,35 +54,21 @@ RasterSource::RasterSource(const RecordingSource* other)
recording_scale_factor_(other->recording_scale_factor_) {}
RasterSource::~RasterSource() = default;
-void RasterSource::ClearForFullRaster(
+void RasterSource::ClearForOpaqueRaster(
SkCanvas* raster_canvas,
const gfx::Size& content_size,
const gfx::Rect& canvas_bitmap_rect,
const gfx::Rect& canvas_playback_rect) const {
- // If this raster source has opaque contents, it is guaranteeing that it
- // will draw an opaque rect the size of the layer. If it is not, then we
- // must clear this canvas ourselves (i.e. requires_clear_).
- if (requires_clear_) {
- TrackRasterSourceNeededClear(RasterSourceClearType::kFull);
- raster_canvas->clear(SK_ColorTRANSPARENT);
- return;
- }
-
// The last texel of this content is not guaranteed to be fully opaque, so
- // inset by one to generate the fully opaque coverage rect . This rect is
+ // inset by one to generate the fully opaque coverage rect. This rect is
// in device space.
SkIRect coverage_device_rect =
SkIRect::MakeWH(content_size.width() - canvas_bitmap_rect.x() - 1,
content_size.height() - canvas_bitmap_rect.y() - 1);
- // Remove playback rect offset, which is equal to bitmap rect offset,
- // as this is full raster.
- SkIRect playback_device_rect = SkIRect::MakeWH(canvas_playback_rect.width(),
- canvas_playback_rect.height());
-
// If not fully covered, we need to clear one texel inside the coverage
- // rect (because of blending during raster) and one texel outside the full
- // raster rect (because of bilinear filtering during draw). See comments
+ // rect (because of blending during raster) and one texel outside the canvas
+ // bitmap rect (because of bilinear filtering during draw). See comments
// in RasterSource.
SkIRect device_column = SkIRect::MakeXYWH(coverage_device_rect.right(), 0, 2,
coverage_device_rect.bottom());
@@ -90,9 +76,22 @@ void RasterSource::ClearForFullRaster(
SkIRect device_row = SkIRect::MakeXYWH(0, coverage_device_rect.bottom(),
coverage_device_rect.right() + 2, 2);
+ bool right_edge = content_size.width() == canvas_playback_rect.right();
+ bool bottom_edge = content_size.height() == canvas_playback_rect.bottom();
+
+ // If the playback rect is touching either edge of the content rect
+ // extend it by one pixel to include the extra texel outside the canvas
+ // bitmap rect that was added to device column and row above.
+ SkIRect playback_device_rect =
+ SkIRect::MakeXYWH(canvas_playback_rect.x() - canvas_bitmap_rect.x(),
+ canvas_playback_rect.y() - canvas_bitmap_rect.y(),
+ canvas_playback_rect.width() + (right_edge ? 1 : 0),
+ canvas_playback_rect.height() + (bottom_edge ? 1 : 0));
+
+ // Intersect the device column and row with the playback rect and only
+ // clear inside of that rect if needed.
RasterSourceClearType clear_type = RasterSourceClearType::kNone;
- // Only bother clearing if we need to.
- if (SkIRect::Intersects(device_column, playback_device_rect)) {
+ if (device_column.intersect(playback_device_rect)) {
clear_type = RasterSourceClearType::kBorder;
raster_canvas->save();
raster_canvas->clipRect(SkRect::MakeFromIRect(device_column),
@@ -100,7 +99,7 @@ void RasterSource::ClearForFullRaster(
raster_canvas->drawColor(background_color_, SkBlendMode::kSrc);
raster_canvas->restore();
}
- if (SkIRect::Intersects(device_row, playback_device_rect)) {
+ if (device_row.intersect(playback_device_rect)) {
clear_type = RasterSourceClearType::kBorder;
raster_canvas->save();
raster_canvas->clipRect(SkRect::MakeFromIRect(device_row),
@@ -136,9 +135,21 @@ void RasterSource::PlaybackToCanvas(
}
bool is_partial_raster = canvas_bitmap_rect != canvas_playback_rect;
- if (!is_partial_raster && settings.clear_canvas_before_raster) {
- ClearForFullRaster(raster_canvas, content_size, canvas_bitmap_rect,
- canvas_playback_rect);
+ if (!requires_clear_) {
+ // Clear opaque raster sources. Opaque rasters sources guarantee that all
+ // pixels inside the opaque region are painted. However, due to scaling
+ // it's possible that the last row and column might include pixels that
+ // are not painted. Because this raster source is required to be opaque,
+ // we may need to do extra clearing outside of the clip. This needs to
+ // be done for both full and partial raster.
+ ClearForOpaqueRaster(raster_canvas, content_size, canvas_bitmap_rect,
+ canvas_playback_rect);
+ } else if (!is_partial_raster) {
+ // For non-opaque raster sources that are rastering the full tile,
+ // just clear the entire canvas (even if stretches past the canvas
+ // bitmap rect) as it's cheap to do so.
+ TrackRasterSourceNeededClear(RasterSourceClearType::kFull);
+ raster_canvas->clear(SK_ColorTRANSPARENT);
}
raster_canvas->save();
@@ -149,10 +160,12 @@ void RasterSource::PlaybackToCanvas(
raster_canvas->scale(raster_transform.scale() / recording_scale_factor_,
raster_transform.scale() / recording_scale_factor_);
- if (is_partial_raster && settings.clear_canvas_before_raster &&
- requires_clear_) {
+ if (is_partial_raster && requires_clear_) {
// TODO(enne): Should this be considered a partial clear?
TrackRasterSourceNeededClear(RasterSourceClearType::kFull);
+ // Because Skia treats painted regions as transparent by default, we don't
+ // need to clear outside of the playback rect in the same way that
+ // ClearForOpaqueRaster must handle.
raster_canvas->clear(SK_ColorTRANSPARENT);
}
diff --git a/chromium/cc/raster/raster_source.h b/chromium/cc/raster/raster_source.h
index 33e0231fc13..0fa0f86484c 100644
--- a/chromium/cc/raster/raster_source.h
+++ b/chromium/cc/raster/raster_source.h
@@ -38,7 +38,6 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
// If set to true, we should use LCD text.
bool use_lcd_text = true;
- bool clear_canvas_before_raster = true;
// The ImageProvider used to replace images during playback.
ImageProvider* image_provider = nullptr;
@@ -133,10 +132,10 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
explicit RasterSource(const RecordingSource* other);
virtual ~RasterSource();
- void ClearForFullRaster(SkCanvas* raster_canvas,
- const gfx::Size& content_size,
- const gfx::Rect& canvas_bitmap_rect,
- const gfx::Rect& canvas_playback_rect) const;
+ void ClearForOpaqueRaster(SkCanvas* raster_canvas,
+ const gfx::Size& content_size,
+ const gfx::Rect& canvas_bitmap_rect,
+ const gfx::Rect& canvas_playback_rect) const;
// These members are const as this raster source may be in use on another
// thread and so should not be touched after construction.
diff --git a/chromium/cc/raster/staging_buffer_pool.cc b/chromium/cc/raster/staging_buffer_pool.cc
index 0ac04f79693..f8da555500e 100644
--- a/chromium/cc/raster/staging_buffer_pool.cc
+++ b/chromium/cc/raster/staging_buffer_pool.cc
@@ -146,7 +146,12 @@ StagingBufferPool::StagingBufferPool(
DCHECK(worker_context_provider_);
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "cc::StagingBufferPool", base::ThreadTaskRunnerHandle::Get());
+
base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
+ memory_pressure_listener_.reset(new base::MemoryPressureListener(
+ base::BindRepeating(&StagingBufferPool::OnMemoryPressure,
+ weak_ptr_factory_.GetWeakPtr())));
+
reduce_memory_usage_callback_ = base::Bind(
&StagingBufferPool::ReduceMemoryUsage, weak_ptr_factory_.GetWeakPtr());
}
@@ -433,4 +438,17 @@ void StagingBufferPool::OnPurgeMemory() {
ReleaseBuffersNotUsedSince(base::TimeTicks() + base::TimeDelta::Max());
}
+void StagingBufferPool::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level) {
+ base::AutoLock lock(lock_);
+ switch (level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ ReleaseBuffersNotUsedSince(base::TimeTicks() + base::TimeDelta::Max());
+ break;
+ }
+}
+
} // namespace cc
diff --git a/chromium/cc/raster/staging_buffer_pool.h b/chromium/cc/raster/staging_buffer_pool.h
index 460a3bbe843..881c34e0acd 100644
--- a/chromium/cc/raster/staging_buffer_pool.h
+++ b/chromium/cc/raster/staging_buffer_pool.h
@@ -13,6 +13,7 @@
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/memory_coordinator_client.h"
+#include "base/memory/memory_pressure_listener.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "base/synchronization/lock.h"
@@ -100,6 +101,11 @@ class CC_EXPORT StagingBufferPool
// Overriden from base::MemoryCoordinatorClient.
void OnPurgeMemory() override;
+ // TODO(gyuyoung): OnMemoryPressure is deprecated. So this should be removed
+ // when the memory coordinator is enabled by default.
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level);
+
scoped_refptr<base::SequencedTaskRunner> task_runner_;
viz::RasterContextProvider* const worker_context_provider_;
const bool use_partial_raster_;
@@ -119,6 +125,8 @@ class CC_EXPORT StagingBufferPool
bool reduce_memory_usage_pending_;
base::Closure reduce_memory_usage_callback_;
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
base::WeakPtrFactory<StagingBufferPool> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(StagingBufferPool);
diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
index fd2bb2118c8..dcb25d7ca28 100644
--- a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
@@ -11,8 +11,8 @@
#include "base/macros.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
-#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/resources/resource_pool.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/resources/platform_color.h"
#include "components/viz/common/resources/resource_format_utils.h"
@@ -104,7 +104,6 @@ class ZeroCopyRasterBufferImpl : public RasterBuffer {
gl->GenTextures(1, &backing_->texture_id);
backing_->texture_target = gpu::GetBufferTextureTarget(
kBufferUsage, viz::BufferFormat(resource_format_), caps);
- backing_->mailbox = gpu::Mailbox::Generate();
gl->ProduceTextureDirectCHROMIUM(backing_->texture_id,
backing_->mailbox.name);
backing_->overlay_candidate = true;
@@ -144,10 +143,15 @@ class ZeroCopyRasterBufferImpl : public RasterBuffer {
backing_->image_id);
gl->BindTexImage2DCHROMIUM(backing_->texture_target, backing_->image_id);
}
+ if (resource_color_space_.IsValid()) {
+ gl->SetColorSpaceMetadataCHROMIUM(
+ backing_->texture_id,
+ reinterpret_cast<GLColorSpace>(&resource_color_space_));
+ }
gl->BindTexture(backing_->texture_target, 0);
backing_->mailbox_sync_token =
- LayerTreeResourceProvider::GenerateSyncTokenHelper(gl);
+ viz::ClientResourceProvider::GenerateSyncTokenHelper(gl);
backing_->gpu_memory_buffer = std::move(gpu_memory_buffer_);
}
@@ -165,10 +169,10 @@ class ZeroCopyRasterBufferImpl : public RasterBuffer {
gpu_memory_buffer_ = gpu_memory_buffer_manager_->CreateGpuMemoryBuffer(
resource_size_, viz::BufferFormat(resource_format_), kBufferUsage,
gpu::kNullSurfaceHandle);
- // GpuMemoryBuffer allocation can fail (https://crbug.com/554541).
+ // Note that GpuMemoryBuffer allocation can fail.
+ // https://crbug.com/554541
if (!gpu_memory_buffer_)
return;
- gpu_memory_buffer_->SetColorSpace(resource_color_space_);
}
DCHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat(
diff --git a/chromium/cc/resources/cross_thread_shared_bitmap.h b/chromium/cc/resources/cross_thread_shared_bitmap.h
index 1a436e91b70..f594ef19df5 100644
--- a/chromium/cc/resources/cross_thread_shared_bitmap.h
+++ b/chromium/cc/resources/cross_thread_shared_bitmap.h
@@ -10,8 +10,8 @@
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "cc/cc_export.h"
-#include "components/viz/common/quads/shared_bitmap.h"
#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/resources/shared_bitmap.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
diff --git a/chromium/cc/resources/layer_tree_resource_provider.cc b/chromium/cc/resources/layer_tree_resource_provider.cc
deleted file mode 100644
index df7c76ca592..00000000000
--- a/chromium/cc/resources/layer_tree_resource_provider.cc
+++ /dev/null
@@ -1,307 +0,0 @@
-// Copyright 2017 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/resources/layer_tree_resource_provider.h"
-
-#include "base/bits.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/resources/resource_format_utils.h"
-#include "components/viz/common/resources/resource_sizes.h"
-#include "components/viz/common/resources/returned_resource.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/command_buffer/client/raster_interface.h"
-#include "gpu/command_buffer/common/capabilities.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-
-using gpu::gles2::GLES2Interface;
-
-namespace cc {
-
-struct LayerTreeResourceProvider::ImportedResource {
- viz::TransferableResource resource;
- std::unique_ptr<viz::SingleReleaseCallback> release_callback;
- int exported_count = 0;
- bool marked_for_deletion = false;
-
- gpu::SyncToken returned_sync_token;
- bool returned_lost = false;
-
- ImportedResource(viz::ResourceId id,
- const viz::TransferableResource& resource,
- std::unique_ptr<viz::SingleReleaseCallback> release_callback)
- : resource(resource),
- release_callback(std::move(release_callback)),
- // If the resource is immediately deleted, it returns the same SyncToken
- // it came with. The client may need to wait on that before deleting the
- // backing or reusing it.
- returned_sync_token(resource.mailbox_holder.sync_token) {
- // Replace the |resource| id with the local id from this
- // LayerTreeResourceProvider.
- this->resource.id = id;
- }
- ~ImportedResource() = default;
-
- ImportedResource(ImportedResource&&) = default;
- ImportedResource& operator=(ImportedResource&&) = default;
-};
-
-LayerTreeResourceProvider::LayerTreeResourceProvider(
- viz::ContextProvider* compositor_context_provider,
- bool delegated_sync_points_required)
- : delegated_sync_points_required_(delegated_sync_points_required),
- compositor_context_provider_(compositor_context_provider) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-LayerTreeResourceProvider::~LayerTreeResourceProvider() {
- for (auto& pair : imported_resources_) {
- ImportedResource& imported = pair.second;
- // If the resource is exported we can't report when it can be used again
- // once this class is destroyed, so consider the resource lost.
- bool is_lost = imported.exported_count || imported.returned_lost;
- imported.release_callback->Run(imported.returned_sync_token, is_lost);
- }
-}
-
-gpu::SyncToken LayerTreeResourceProvider::GenerateSyncTokenHelper(
- gpu::gles2::GLES2Interface* gl) {
- DCHECK(gl);
- gpu::SyncToken sync_token;
- gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
- DCHECK(sync_token.HasData() ||
- gl->GetGraphicsResetStatusKHR() != GL_NO_ERROR);
- return sync_token;
-}
-
-gpu::SyncToken LayerTreeResourceProvider::GenerateSyncTokenHelper(
- gpu::raster::RasterInterface* ri) {
- DCHECK(ri);
- gpu::SyncToken sync_token;
- ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
- DCHECK(sync_token.HasData() ||
- ri->GetGraphicsResetStatusKHR() != GL_NO_ERROR);
- return sync_token;
-}
-
-void LayerTreeResourceProvider::PrepareSendToParent(
- const std::vector<viz::ResourceId>& export_ids,
- std::vector<viz::TransferableResource>* list,
- viz::ContextProvider* context_provider) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- // This function goes through the array multiple times, store the resources
- // as pointers so we don't have to look up the resource id multiple times.
- // Make sure the maps do not change while these vectors are alive or they
- // will become invalid.
- std::vector<ImportedResource*> imports;
- imports.reserve(export_ids.size());
- for (const viz::ResourceId id : export_ids) {
- auto it = imported_resources_.find(id);
- DCHECK(it != imported_resources_.end());
- imports.push_back(&it->second);
- }
-
- // Lazily create any mailboxes and verify all unverified sync tokens.
- std::vector<GLbyte*> unverified_sync_tokens;
- if (delegated_sync_points_required_) {
- for (ImportedResource* imported : imports) {
- if (!imported->resource.is_software &&
- !imported->resource.mailbox_holder.sync_token.verified_flush()) {
- unverified_sync_tokens.push_back(
- imported->resource.mailbox_holder.sync_token.GetData());
- }
- }
- }
-
- if (!unverified_sync_tokens.empty()) {
- DCHECK(delegated_sync_points_required_);
- DCHECK(context_provider);
- context_provider->ContextGL()->VerifySyncTokensCHROMIUM(
- unverified_sync_tokens.data(), unverified_sync_tokens.size());
- }
-
- for (ImportedResource* imported : imports) {
- list->push_back(imported->resource);
- imported->exported_count++;
- }
-}
-
-void LayerTreeResourceProvider::ReceiveReturnsFromParent(
- const std::vector<viz::ReturnedResource>& resources) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- for (const viz::ReturnedResource& returned : resources) {
- viz::ResourceId local_id = returned.id;
-
- auto import_it = imported_resources_.find(local_id);
- DCHECK(import_it != imported_resources_.end());
- ImportedResource& imported = import_it->second;
-
- DCHECK_GE(imported.exported_count, returned.count);
- imported.exported_count -= returned.count;
- imported.returned_lost |= returned.lost;
-
- if (imported.exported_count)
- continue;
-
- if (returned.sync_token.HasData()) {
- DCHECK(!imported.resource.is_software);
- imported.returned_sync_token = returned.sync_token;
- }
-
- if (imported.marked_for_deletion) {
- imported.release_callback->Run(imported.returned_sync_token,
- imported.returned_lost);
- imported_resources_.erase(import_it);
- }
- }
-}
-
-viz::ResourceId LayerTreeResourceProvider::ImportResource(
- const viz::TransferableResource& resource,
- std::unique_ptr<viz::SingleReleaseCallback> release_callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- viz::ResourceId id = next_id_++;
- auto result = imported_resources_.emplace(
- id, ImportedResource(id, resource, std::move(release_callback)));
- DCHECK(result.second); // If false, the id was already in the map.
- return id;
-}
-
-void LayerTreeResourceProvider::RemoveImportedResource(viz::ResourceId id) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- auto it = imported_resources_.find(id);
- DCHECK(it != imported_resources_.end());
- ImportedResource& imported = it->second;
- imported.marked_for_deletion = true;
- if (imported.exported_count == 0) {
- imported.release_callback->Run(imported.returned_sync_token,
- imported.returned_lost);
- imported_resources_.erase(it);
- }
-}
-
-bool LayerTreeResourceProvider::IsTextureFormatSupported(
- viz::ResourceFormat format) const {
- gpu::Capabilities caps;
- if (compositor_context_provider_)
- caps = compositor_context_provider_->ContextCapabilities();
-
- switch (format) {
- case viz::ALPHA_8:
- case viz::RGBA_4444:
- case viz::RGBA_8888:
- case viz::RGB_565:
- case viz::LUMINANCE_8:
- return true;
- case viz::BGRA_8888:
- return caps.texture_format_bgra8888;
- case viz::ETC1:
- return caps.texture_format_etc1;
- case viz::RED_8:
- return caps.texture_rg;
- case viz::R16_EXT:
- return caps.texture_norm16;
- case viz::LUMINANCE_F16:
- case viz::RGBA_F16:
- return caps.texture_half_float_linear;
- }
-
- NOTREACHED();
- return false;
-}
-
-bool LayerTreeResourceProvider::IsRenderBufferFormatSupported(
- viz::ResourceFormat format) const {
- gpu::Capabilities caps;
- if (compositor_context_provider_)
- caps = compositor_context_provider_->ContextCapabilities();
-
- switch (format) {
- case viz::RGBA_4444:
- case viz::RGBA_8888:
- case viz::RGB_565:
- return true;
- case viz::BGRA_8888:
- return caps.render_buffer_format_bgra8888;
- case viz::RGBA_F16:
- // TODO(ccameron): This will always return false on pixel tests, which
- // makes it un-test-able until we upgrade Mesa.
- // https://crbug.com/687720
- return caps.texture_half_float_linear &&
- caps.color_buffer_half_float_rgba;
- case viz::LUMINANCE_8:
- case viz::ALPHA_8:
- case viz::RED_8:
- case viz::ETC1:
- case viz::LUMINANCE_F16:
- case viz::R16_EXT:
- // We don't currently render into these formats. If we need to render into
- // these eventually, we should expand this logic.
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
-LayerTreeResourceProvider::ScopedSkSurface::ScopedSkSurface(
- GrContext* gr_context,
- GLuint texture_id,
- GLenum texture_target,
- const gfx::Size& size,
- viz::ResourceFormat format,
- bool can_use_lcd_text,
- int msaa_sample_count) {
- GrGLTextureInfo texture_info;
- texture_info.fID = texture_id;
- texture_info.fTarget = texture_target;
- texture_info.fFormat = TextureStorageFormat(format);
- GrBackendTexture backend_texture(size.width(), size.height(),
- GrMipMapped::kNo, texture_info);
- SkSurfaceProps surface_props = ComputeSurfaceProps(can_use_lcd_text);
- // This type is used only for gpu raster, which implies gpu compositing.
- bool gpu_compositing = true;
- surface_ = SkSurface::MakeFromBackendTextureAsRenderTarget(
- gr_context, backend_texture, kTopLeft_GrSurfaceOrigin, msaa_sample_count,
- ResourceFormatToClosestSkColorType(gpu_compositing, format), nullptr,
- &surface_props);
-}
-
-LayerTreeResourceProvider::ScopedSkSurface::~ScopedSkSurface() {
- if (surface_)
- surface_->prepareForExternalIO();
-}
-
-SkSurfaceProps LayerTreeResourceProvider::ScopedSkSurface::ComputeSurfaceProps(
- bool can_use_lcd_text) {
- uint32_t flags = 0;
- // Use unknown pixel geometry to disable LCD text.
- SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
- if (can_use_lcd_text) {
- // LegacyFontHost will get LCD text and skia figures out what type to use.
- surface_props =
- SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
- }
- return surface_props;
-}
-
-void LayerTreeResourceProvider::ValidateResource(viz::ResourceId id) const {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(id);
- DCHECK(imported_resources_.find(id) != imported_resources_.end());
-}
-
-bool LayerTreeResourceProvider::InUseByConsumer(viz::ResourceId id) {
- auto it = imported_resources_.find(id);
- DCHECK(it != imported_resources_.end());
- ImportedResource& imported = it->second;
- return imported.exported_count > 0 || imported.returned_lost;
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/layer_tree_resource_provider.h b/chromium/cc/resources/layer_tree_resource_provider.h
deleted file mode 100644
index b046ea9d33c..00000000000
--- a/chromium/cc/resources/layer_tree_resource_provider.h
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2017 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_RESOURCES_LAYER_TREE_RESOURCE_PROVIDER_H_
-#define CC_RESOURCES_LAYER_TREE_RESOURCE_PROVIDER_H_
-
-#include <vector>
-
-#include "base/threading/thread_checker.h"
-#include "cc/cc_export.h"
-#include "components/viz/common/display/renderer_settings.h"
-#include "components/viz/common/resources/release_callback.h"
-#include "components/viz/common/resources/resource_id.h"
-#include "components/viz/common/resources/resource_settings.h"
-#include "components/viz/common/resources/single_release_callback.h"
-#include "components/viz/common/resources/transferable_resource.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/skia/include/core/SkSurface.h"
-#include "third_party/skia/include/gpu/GrBackendSurface.h"
-#include "third_party/skia/include/gpu/GrContext.h"
-
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-namespace raster {
-class RasterInterface;
-}
-} // namespace gpu
-
-namespace viz {
-class ContextProvider;
-} // namespace viz
-
-namespace cc {
-
-// This class is not thread-safe and can only be called from the thread it was
-// created on (in practice, the impl thread).
-class CC_EXPORT LayerTreeResourceProvider {
- public:
- LayerTreeResourceProvider(viz::ContextProvider* compositor_context_provider,
- bool delegated_sync_points_required);
- ~LayerTreeResourceProvider();
-
- static gpu::SyncToken GenerateSyncTokenHelper(gpu::gles2::GLES2Interface* gl);
- static gpu::SyncToken GenerateSyncTokenHelper(
- gpu::raster::RasterInterface* ri);
-
- // Prepares resources to be transfered to the parent, moving them to
- // mailboxes and serializing meta-data into TransferableResources.
- // Resources are not removed from the ResourceProvider, but are marked as
- // "in use".
- void PrepareSendToParent(
- const std::vector<viz::ResourceId>& resource_ids,
- std::vector<viz::TransferableResource>* transferable_resources,
- viz::ContextProvider* context_provider);
-
- // Receives resources from the parent, moving them from mailboxes. ResourceIds
- // passed are in the child namespace.
- // NOTE: if the sync_token is set on any viz::TransferableResource, this will
- // wait on it.
- void ReceiveReturnsFromParent(
- const std::vector<viz::ReturnedResource>& transferable_resources);
-
- // Receives a resource from an external client that can be used in compositor
- // frames, via the returned ResourceId.
- viz::ResourceId ImportResource(const viz::TransferableResource&,
- std::unique_ptr<viz::SingleReleaseCallback>);
- // Removes an imported resource, which will call the ReleaseCallback given
- // originally, once the resource is no longer in use by any compositor frame.
- void RemoveImportedResource(viz::ResourceId);
-
- // Verify that the ResourceId is valid and is known to this class, for debug
- // checks.
- void ValidateResource(viz::ResourceId id) const;
-
- // Checks whether a resource is in use by a consumer.
- bool InUseByConsumer(viz::ResourceId id);
-
- bool IsTextureFormatSupported(viz::ResourceFormat format) const;
-
- // Returns true if the provided |format| can be used as a render buffer.
- // Note that render buffer support implies texture support.
- bool IsRenderBufferFormatSupported(viz::ResourceFormat format) const;
-
- bool IsSoftware() const { return !compositor_context_provider_; }
-
- class CC_EXPORT ScopedSkSurface {
- public:
- ScopedSkSurface(GrContext* gr_context,
- GLuint texture_id,
- GLenum texture_target,
- const gfx::Size& size,
- viz::ResourceFormat format,
- bool can_use_lcd_text,
- int msaa_sample_count);
- ~ScopedSkSurface();
-
- SkSurface* surface() const { return surface_.get(); }
-
- static SkSurfaceProps ComputeSurfaceProps(bool can_use_lcd_text);
-
- private:
- sk_sp<SkSurface> surface_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedSkSurface);
- };
-
- private:
- struct ImportedResource;
-
- THREAD_CHECKER(thread_checker_);
- const bool delegated_sync_points_required_;
- viz::ContextProvider* const compositor_context_provider_;
-
- base::flat_map<viz::ResourceId, ImportedResource> imported_resources_;
- // The ResourceIds in LayerTreeResourceProvider start from 1 to avoid
- // conflicts with id from viz::DisplayResourceProvider.
- viz::ResourceId next_id_ = 1;
-
- DISALLOW_COPY_AND_ASSIGN(LayerTreeResourceProvider);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_LAYER_TREE_RESOURCE_PROVIDER_H_
diff --git a/chromium/cc/resources/layer_tree_resource_provider_unittest.cc b/chromium/cc/resources/layer_tree_resource_provider_unittest.cc
deleted file mode 100644
index e78f363d6b8..00000000000
--- a/chromium/cc/resources/layer_tree_resource_provider_unittest.cc
+++ /dev/null
@@ -1,556 +0,0 @@
-// Copyright 2017 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/resources/layer_tree_resource_provider.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "components/viz/common/resources/returned_resource.h"
-#include "components/viz/common/resources/single_release_callback.h"
-#include "components/viz/test/test_context_provider.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-
-namespace cc {
-namespace {
-
-class LayerTreeResourceProviderTest : public testing::TestWithParam<bool> {
- protected:
- LayerTreeResourceProviderTest()
- : use_gpu_(GetParam()),
- context_provider_(viz::TestContextProvider::Create()),
- bound_(context_provider_->BindToCurrentThread()),
- provider_(std::make_unique<LayerTreeResourceProvider>(
- use_gpu_ ? context_provider_.get() : nullptr,
- delegated_sync_points_required_)) {
- DCHECK_EQ(bound_, gpu::ContextResult::kSuccess);
- }
-
- gpu::Mailbox MailboxFromChar(char value) {
- gpu::Mailbox mailbox;
- memset(mailbox.name, value, sizeof(mailbox.name));
- return mailbox;
- }
-
- gpu::SyncToken SyncTokenFromUInt(uint32_t value) {
- return gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x123), value);
- }
-
- viz::TransferableResource MakeTransferableResource(
- bool gpu,
- char mailbox_char,
- uint32_t sync_token_value) {
- viz::TransferableResource r;
- r.id = mailbox_char;
- r.is_software = !gpu;
- r.filter = 456;
- r.size = gfx::Size(10, 11);
- r.mailbox_holder.mailbox = MailboxFromChar(mailbox_char);
- if (gpu) {
- r.mailbox_holder.sync_token = SyncTokenFromUInt(sync_token_value);
- r.mailbox_holder.texture_target = 6;
- }
- return r;
- }
-
- void Shutdown() { provider_.reset(); }
-
- bool use_gpu() const { return use_gpu_; }
- LayerTreeResourceProvider& provider() const { return *provider_; }
- viz::ContextProvider* context_provider() const {
- return context_provider_.get();
- }
-
- void DestroyProvider() { provider_.reset(); }
-
- private:
- bool use_gpu_;
- scoped_refptr<viz::TestContextProvider> context_provider_;
- gpu::ContextResult bound_;
- bool delegated_sync_points_required_ = true;
- std::unique_ptr<LayerTreeResourceProvider> provider_;
-};
-
-INSTANTIATE_TEST_CASE_P(LayerTreeResourceProviderTests,
- LayerTreeResourceProviderTest,
- ::testing::Values(false, true));
-
-class MockReleaseCallback {
- public:
- MOCK_METHOD2(Released, void(const gpu::SyncToken& token, bool lost));
-};
-
-TEST_P(LayerTreeResourceProviderTest, TransferableResourceReleased) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId id = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
- // The local id is different.
- EXPECT_NE(id, tran.id);
-
- // The same SyncToken that was sent is returned when the resource was never
- // exported. The SyncToken may be from any context, and the ReleaseCallback
- // may need to wait on it before interacting with the resource on its context.
- EXPECT_CALL(release, Released(tran.mailbox_holder.sync_token, false));
- provider().RemoveImportedResource(id);
-}
-
-TEST_P(LayerTreeResourceProviderTest, TransferableResourceSendToParent) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- tran.buffer_format = gfx::BufferFormat::RGBX_8888;
- viz::ResourceId id = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Export the resource.
- std::vector<viz::ResourceId> to_send = {id};
- std::vector<viz::TransferableResource> exported;
- provider().PrepareSendToParent(to_send, &exported, context_provider());
- ASSERT_EQ(exported.size(), 1u);
-
- // Exported resource matches except for the id which was mapped
- // to the local ResourceProvider, and the sync token should be
- // verified if it's a gpu resource.
- gpu::SyncToken verified_sync_token = tran.mailbox_holder.sync_token;
- if (!tran.is_software)
- verified_sync_token.SetVerifyFlush();
- EXPECT_EQ(exported[0].id, id);
- EXPECT_EQ(exported[0].is_software, tran.is_software);
- EXPECT_EQ(exported[0].filter, tran.filter);
- EXPECT_EQ(exported[0].size, tran.size);
- EXPECT_EQ(exported[0].mailbox_holder.mailbox, tran.mailbox_holder.mailbox);
- EXPECT_EQ(exported[0].mailbox_holder.sync_token, verified_sync_token);
- EXPECT_EQ(exported[0].mailbox_holder.texture_target,
- tran.mailbox_holder.texture_target);
- EXPECT_EQ(exported[0].buffer_format, tran.buffer_format);
-
- // Exported resources are not released when removed, until the export returns.
- EXPECT_CALL(release, Released(_, _)).Times(0);
- provider().RemoveImportedResource(id);
-
- // Return the resource, with a sync token if using gpu.
- std::vector<viz::ReturnedResource> returned;
- returned.push_back({});
- returned.back().id = exported[0].id;
- if (use_gpu())
- returned.back().sync_token = SyncTokenFromUInt(31);
- returned.back().count = 1;
- returned.back().lost = false;
-
- // The sync token is given to the ReleaseCallback.
- EXPECT_CALL(release, Released(returned[0].sync_token, false));
- provider().ReceiveReturnsFromParent(returned);
-}
-
-TEST_P(LayerTreeResourceProviderTest, TransferableResourceSendTwoToParent) {
- viz::TransferableResource tran[] = {
- MakeTransferableResource(use_gpu(), 'a', 15),
- MakeTransferableResource(use_gpu(), 'b', 16)};
- viz::ResourceId id1 = provider().ImportResource(
- tran[0], viz::SingleReleaseCallback::Create(base::DoNothing()));
- viz::ResourceId id2 = provider().ImportResource(
- tran[1], viz::SingleReleaseCallback::Create(base::DoNothing()));
-
- // Export the resource.
- std::vector<viz::ResourceId> to_send = {id1, id2};
- std::vector<viz::TransferableResource> exported;
- provider().PrepareSendToParent(to_send, &exported, context_provider());
- ASSERT_EQ(exported.size(), 2u);
-
- // Exported resource matches except for the id which was mapped
- // to the local ResourceProvider, and the sync token should be
- // verified if it's a gpu resource.
- for (int i = 0; i < 2; ++i) {
- gpu::SyncToken verified_sync_token = tran[i].mailbox_holder.sync_token;
- if (!tran[i].is_software)
- verified_sync_token.SetVerifyFlush();
- EXPECT_EQ(exported[i].id, to_send[i]);
- EXPECT_EQ(exported[i].is_software, tran[i].is_software);
- EXPECT_EQ(exported[i].filter, tran[i].filter);
- EXPECT_EQ(exported[i].size, tran[i].size);
- EXPECT_EQ(exported[i].mailbox_holder.mailbox,
- tran[i].mailbox_holder.mailbox);
- EXPECT_EQ(exported[i].mailbox_holder.sync_token, verified_sync_token);
- EXPECT_EQ(exported[i].mailbox_holder.texture_target,
- tran[i].mailbox_holder.texture_target);
- EXPECT_EQ(exported[i].buffer_format, tran[i].buffer_format);
- }
-}
-
-TEST_P(LayerTreeResourceProviderTest,
- TransferableResourceSendToParentTwoTimes) {
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId id = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::DoNothing()));
-
- // Export the resource.
- std::vector<viz::ResourceId> to_send = {id};
- std::vector<viz::TransferableResource> exported;
- provider().PrepareSendToParent(to_send, &exported, context_provider());
- ASSERT_EQ(exported.size(), 1u);
- EXPECT_EQ(exported[0].id, id);
-
- // Return the resource, with a sync token if using gpu.
- std::vector<viz::ReturnedResource> returned;
- returned.push_back({});
- returned.back().id = exported[0].id;
- if (use_gpu())
- returned.back().sync_token = SyncTokenFromUInt(31);
- returned.back().count = 1;
- returned.back().lost = false;
- provider().ReceiveReturnsFromParent(returned);
-
- // Then export again, it still sends.
- exported.clear();
- provider().PrepareSendToParent(to_send, &exported, context_provider());
- ASSERT_EQ(exported.size(), 1u);
- EXPECT_EQ(exported[0].id, id);
-}
-
-TEST_P(LayerTreeResourceProviderTest,
- TransferableResourceLostOnShutdownIfExported) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId id = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Export the resource.
- std::vector<viz::ResourceId> to_send = {id};
- std::vector<viz::TransferableResource> exported;
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- EXPECT_CALL(release, Released(_, true));
- Shutdown();
-}
-
-TEST_P(LayerTreeResourceProviderTest, TransferableResourceRemovedAfterReturn) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId id = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Export the resource.
- std::vector<viz::ResourceId> to_send = {id};
- std::vector<viz::TransferableResource> exported;
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- // Return the resource. This does not release the resource back to
- // the client.
- std::vector<viz::ReturnedResource> returned;
- returned.push_back({});
- returned.back().id = exported[0].id;
- if (use_gpu())
- returned.back().sync_token = SyncTokenFromUInt(31);
- returned.back().count = 1;
- returned.back().lost = false;
-
- EXPECT_CALL(release, Released(_, _)).Times(0);
- provider().ReceiveReturnsFromParent(returned);
-
- // Once removed, the resource is released.
- EXPECT_CALL(release, Released(returned[0].sync_token, false));
- provider().RemoveImportedResource(id);
-}
-
-TEST_P(LayerTreeResourceProviderTest, TransferableResourceExportedTwice) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId id = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Export the resource once.
- std::vector<viz::ResourceId> to_send = {id};
- std::vector<viz::TransferableResource> exported;
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- // Exported resources are not released when removed, until all exports are
- // returned.
- EXPECT_CALL(release, Released(_, _)).Times(0);
- provider().RemoveImportedResource(id);
-
- // Export the resource twice.
- exported = {};
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- // Return the resource the first time.
- std::vector<viz::ReturnedResource> returned;
- returned.push_back({});
- returned.back().id = exported[0].id;
- if (use_gpu())
- returned.back().sync_token = SyncTokenFromUInt(31);
- returned.back().count = 1;
- returned.back().lost = false;
- provider().ReceiveReturnsFromParent(returned);
-
- // And a second time, with a different sync token. Now the ReleaseCallback can
- // happen, using the latest sync token.
- if (use_gpu())
- returned.back().sync_token = SyncTokenFromUInt(47);
- EXPECT_CALL(release, Released(returned[0].sync_token, false));
- provider().ReceiveReturnsFromParent(returned);
-}
-
-TEST_P(LayerTreeResourceProviderTest, TransferableResourceReturnedTwiceAtOnce) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId id = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Export the resource once.
- std::vector<viz::ResourceId> to_send = {id};
- std::vector<viz::TransferableResource> exported;
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- // Exported resources are not released when removed, until all exports are
- // returned.
- EXPECT_CALL(release, Released(_, _)).Times(0);
- provider().RemoveImportedResource(id);
-
- // Export the resource twice.
- exported = {};
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- // Return both exports at once.
- std::vector<viz::ReturnedResource> returned;
- returned.push_back({});
- returned.back().id = exported[0].id;
- if (use_gpu())
- returned.back().sync_token = SyncTokenFromUInt(31);
- returned.back().count = 2;
- returned.back().lost = false;
-
- // When returned, the ReleaseCallback can happen, using the latest sync token.
- EXPECT_CALL(release, Released(returned[0].sync_token, false));
- provider().ReceiveReturnsFromParent(returned);
-}
-
-TEST_P(LayerTreeResourceProviderTest, TransferableResourceLostOnReturn) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId id = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Export the resource once.
- std::vector<viz::ResourceId> to_send = {id};
- std::vector<viz::TransferableResource> exported;
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- // Exported resources are not released when removed, until all exports are
- // returned.
- EXPECT_CALL(release, Released(_, _)).Times(0);
- provider().RemoveImportedResource(id);
-
- // Export the resource twice.
- exported = {};
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- // Return the resource the first time, not lost.
- std::vector<viz::ReturnedResource> returned;
- returned.push_back({});
- returned.back().id = exported[0].id;
- returned.back().count = 1;
- returned.back().lost = false;
- provider().ReceiveReturnsFromParent(returned);
-
- // Return a second time, as lost. The viz::ReturnCallback should report it
- // lost.
- returned.back().lost = true;
- EXPECT_CALL(release, Released(_, true));
- provider().ReceiveReturnsFromParent(returned);
-}
-
-TEST_P(LayerTreeResourceProviderTest, TransferableResourceLostOnFirstReturn) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId id = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Export the resource once.
- std::vector<viz::ResourceId> to_send = {id};
- std::vector<viz::TransferableResource> exported;
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- // Exported resources are not released when removed, until all exports are
- // returned.
- EXPECT_CALL(release, Released(_, _)).Times(0);
- provider().RemoveImportedResource(id);
-
- // Export the resource twice.
- exported = {};
- provider().PrepareSendToParent(to_send, &exported, context_provider());
-
- // Return the resource the first time, marked as lost.
- std::vector<viz::ReturnedResource> returned;
- returned.push_back({});
- returned.back().id = exported[0].id;
- returned.back().count = 1;
- returned.back().lost = true;
- provider().ReceiveReturnsFromParent(returned);
-
- // Return a second time, not lost. The first lost signal should not be lost.
- returned.back().lost = false;
- EXPECT_CALL(release, Released(_, true));
- provider().ReceiveReturnsFromParent(returned);
-}
-
-TEST_P(LayerTreeResourceProviderTest, ReturnedSyncTokensArePassedToClient) {
- // SyncTokens are gpu-only.
- if (!use_gpu())
- return;
-
- MockReleaseCallback release;
-
- GLuint texture;
- context_provider()->ContextGL()->GenTextures(1, &texture);
- context_provider()->ContextGL()->BindTexture(GL_TEXTURE_2D, texture);
- gpu::Mailbox mailbox;
- context_provider()->ContextGL()->GenMailboxCHROMIUM(mailbox.name);
- context_provider()->ContextGL()->ProduceTextureDirectCHROMIUM(texture,
- mailbox.name);
- gpu::SyncToken sync_token;
- context_provider()->ContextGL()->GenSyncTokenCHROMIUM(sync_token.GetData());
-
- auto tran = viz::TransferableResource::MakeGL(mailbox, GL_LINEAR,
- GL_TEXTURE_2D, sync_token);
- viz::ResourceId resource = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- EXPECT_TRUE(tran.mailbox_holder.sync_token.HasData());
- // All the logic below assumes that the sync token releases are all positive.
- EXPECT_LT(0u, tran.mailbox_holder.sync_token.release_count());
-
- // Transfer the resource, expect the sync points to be consistent.
- std::vector<viz::TransferableResource> list;
- provider().PrepareSendToParent({resource}, &list, context_provider());
- ASSERT_EQ(1u, list.size());
- EXPECT_LE(sync_token.release_count(),
- list[0].mailbox_holder.sync_token.release_count());
- EXPECT_EQ(0, memcmp(mailbox.name, list[0].mailbox_holder.mailbox.name,
- sizeof(mailbox.name)));
-
- // Make a new texture id from the mailbox.
- context_provider()->ContextGL()->WaitSyncTokenCHROMIUM(
- list[0].mailbox_holder.sync_token.GetConstData());
- unsigned other_texture =
- context_provider()->ContextGL()->CreateAndConsumeTextureCHROMIUM(
- mailbox.name);
- // Then delete it and make a new SyncToken.
- context_provider()->ContextGL()->DeleteTextures(1, &other_texture);
- context_provider()->ContextGL()->GenSyncTokenCHROMIUM(
- list[0].mailbox_holder.sync_token.GetData());
- EXPECT_TRUE(list[0].mailbox_holder.sync_token.HasData());
-
- // Receive the resource, then delete it, expect the SyncTokens to be
- // consistent.
- provider().ReceiveReturnsFromParent(
- viz::TransferableResource::ReturnResources(list));
-
- gpu::SyncToken returned_sync_token;
- EXPECT_CALL(release, Released(_, false))
- .WillOnce(testing::SaveArg<0>(&returned_sync_token));
- provider().RemoveImportedResource(resource);
- EXPECT_GE(returned_sync_token.release_count(),
- list[0].mailbox_holder.sync_token.release_count());
-}
-
-TEST_P(LayerTreeResourceProviderTest, LostResourcesAreReturnedLost) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId resource = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Transfer the resource to the parent.
- std::vector<viz::TransferableResource> list;
- provider().PrepareSendToParent({resource}, &list, context_provider());
- EXPECT_EQ(1u, list.size());
-
- // Receive it back marked lost.
- std::vector<viz::ReturnedResource> returned_to_child;
- returned_to_child.push_back(list[0].ToReturnedResource());
- returned_to_child.back().lost = true;
- provider().ReceiveReturnsFromParent(returned_to_child);
-
- // Delete the resource in the child. Expect the resource to be lost.
- EXPECT_CALL(release, Released(_, true));
- provider().RemoveImportedResource(resource);
-}
-
-TEST_P(LayerTreeResourceProviderTest, ShutdownPreservesLostState) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId resource = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Transfer the resource to the parent.
- std::vector<viz::TransferableResource> list;
- provider().PrepareSendToParent({resource}, &list, context_provider());
- EXPECT_EQ(1u, list.size());
-
- // Receive it back marked lost.
- std::vector<viz::ReturnedResource> returned_to_child;
- returned_to_child.push_back(list[0].ToReturnedResource());
- returned_to_child.back().lost = true;
- provider().ReceiveReturnsFromParent(returned_to_child);
-
- // Shutdown, and expect the resource to be lost..
- EXPECT_CALL(release, Released(_, true));
- DestroyProvider();
-}
-
-TEST_P(LayerTreeResourceProviderTest, ShutdownLosesExportedResources) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId resource = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Transfer the resource to the parent.
- std::vector<viz::TransferableResource> list;
- provider().PrepareSendToParent({resource}, &list, context_provider());
- EXPECT_EQ(1u, list.size());
-
- // Destroy the LayerTreeResourceProvider, the resource is returned lost.
- EXPECT_CALL(release, Released(_, true));
- DestroyProvider();
-}
-
-TEST_P(LayerTreeResourceProviderTest, ShutdownDoesNotLoseUnexportedResources) {
- MockReleaseCallback release;
- viz::TransferableResource tran = MakeTransferableResource(use_gpu(), 'a', 15);
- viz::ResourceId resource = provider().ImportResource(
- tran, viz::SingleReleaseCallback::Create(base::BindOnce(
- &MockReleaseCallback::Released, base::Unretained(&release))));
-
- // Transfer the resource to the parent.
- std::vector<viz::TransferableResource> list;
- provider().PrepareSendToParent({resource}, &list, context_provider());
- EXPECT_EQ(1u, list.size());
-
- // Receive it back.
- provider().ReceiveReturnsFromParent(
- viz::TransferableResource::ReturnResources(list));
-
- // Destroy the LayerTreeResourceProvider, the resource is not lost.
- EXPECT_CALL(release, Released(_, false));
- DestroyProvider();
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc
index a6d8b841c92..47f776cc9d3 100644
--- a/chromium/cc/resources/resource_pool.cc
+++ b/chromium/cc/resources/resource_pool.cc
@@ -20,7 +20,7 @@
#include "base/trace_event/memory_dump_manager.h"
#include "build/build_config.h"
#include "cc/base/container_util.h"
-#include "cc/resources/layer_tree_resource_provider.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -50,8 +50,8 @@ bool ResourceMeetsSizeRequirements(const gfx::Size& requested_size,
return false;
// GetArea will crash on overflow, however all sizes in use are tile sizes.
- // These are capped at LayerTreeResourceProvider::max_texture_size(), and will
- // not overflow.
+ // These are capped at viz::ClientResourceProvider::max_texture_size(), and
+ // will not overflow.
float actual_area = actual_size.GetArea();
float requested_area = requested_size.GetArea();
// Don't use a resource that is more than |kReuseThreshold| times the
@@ -67,7 +67,7 @@ bool ResourceMeetsSizeRequirements(const gfx::Size& requested_size,
constexpr base::TimeDelta ResourcePool::kDefaultExpirationDelay;
ResourcePool::ResourcePool(
- LayerTreeResourceProvider* resource_provider,
+ viz::ClientResourceProvider* resource_provider,
viz::ContextProvider* context_provider,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const base::TimeDelta& expiration_delay,
@@ -83,6 +83,9 @@ ResourcePool::ResourcePool(
this, "cc::ResourcePool", task_runner_.get());
// Register this component with base::MemoryCoordinatorClientRegistry.
base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
+ memory_pressure_listener_.reset(
+ new base::MemoryPressureListener(base::BindRepeating(
+ &ResourcePool::OnMemoryPressure, weak_ptr_factory_.GetWeakPtr())));
}
ResourcePool::~ResourcePool() {
@@ -306,7 +309,6 @@ void ResourcePool::PrepareForExport(const InUsePoolResource& resource) {
resource.resource_->size(), resource.resource_->format());
}
transferable.format = resource.resource_->format();
- transferable.buffer_format = viz::BufferFormat(transferable.format);
transferable.color_space = resource.resource_->color_space();
resource.resource_->set_resource_id(resource_provider_->ImportResource(
std::move(transferable),
@@ -557,6 +559,18 @@ void ResourcePool::OnMemoryStateChange(base::MemoryState state) {
evict_busy_resources_when_unused_ = state == base::MemoryState::SUSPENDED;
}
+void ResourcePool::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level) {
+ switch (level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ EvictResourcesNotUsedSince(base::TimeTicks() + base::TimeDelta::Max());
+ break;
+ }
+}
+
ResourcePool::PoolResource::PoolResource(size_t unique_id,
const gfx::Size& size,
viz::ResourceFormat format,
@@ -571,7 +585,7 @@ ResourcePool::PoolResource::~PoolResource() = default;
void ResourcePool::PoolResource::OnMemoryDump(
base::trace_event::ProcessMemoryDump* pmd,
int tracing_id,
- const LayerTreeResourceProvider* resource_provider,
+ const viz::ClientResourceProvider* resource_provider,
bool is_free) const {
base::UnguessableToken shm_guid;
base::trace_event::MemoryAllocatorDumpGuid backing_guid;
diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h
index e401582bc6d..ebc1f56eabe 100644
--- a/chromium/cc/resources/resource_pool.h
+++ b/chromium/cc/resources/resource_pool.h
@@ -14,15 +14,16 @@
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/memory_coordinator_client.h"
+#include "base/memory/memory_pressure_listener.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/unguessable_token.h"
#include "cc/cc_export.h"
-#include "components/viz/common/quads/shared_bitmap.h"
#include "components/viz/common/resources/resource_format.h"
#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/common/resources/shared_bitmap.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/gfx/color_space.h"
@@ -34,11 +35,11 @@ class SingleThreadTaskRunner;
}
namespace viz {
+class ClientResourceProvider;
class ContextProvider;
}
namespace cc {
-class LayerTreeResourceProvider;
class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
public base::MemoryCoordinatorClient {
@@ -169,7 +170,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
// When holding gpu resources, the |context_provider| should be non-null,
// and when holding software resources, it should be null. It is used for
// consistency checking as well as for correctness.
- ResourcePool(LayerTreeResourceProvider* resource_provider,
+ ResourcePool(viz::ClientResourceProvider* resource_provider,
viz::ContextProvider* context_provider,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const base::TimeDelta& expiration_delay,
@@ -226,6 +227,11 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
void OnPurgeMemory() override;
void OnMemoryStateChange(base::MemoryState state) override;
+ // TODO(gyuyoung): OnMemoryPressure is deprecated. So this should be removed
+ // when the memory coordinator is enabled by default.
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level);
+
size_t GetTotalMemoryUsageForTesting() const {
return total_memory_usage_bytes_;
}
@@ -286,7 +292,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
int tracing_id,
- const LayerTreeResourceProvider* resource_provider,
+ const viz::ClientResourceProvider* resource_provider,
bool is_free) const;
private:
@@ -347,7 +353,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
bool HasEvictableResources() const;
base::TimeTicks GetUsageTimeForLRUResource() const;
- LayerTreeResourceProvider* const resource_provider_;
+ viz::ClientResourceProvider* const resource_provider_;
viz::ContextProvider* const context_provider_;
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
const base::TimeDelta resource_expiration_delay_;
@@ -370,6 +376,8 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
// Map from the PoolResource |unique_id| to the PoolResource.
std::map<size_t, std::unique_ptr<PoolResource>> in_use_resources_;
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
base::WeakPtrFactory<ResourcePool> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ResourcePool);
diff --git a/chromium/cc/resources/resource_pool_unittest.cc b/chromium/cc/resources/resource_pool_unittest.cc
index 509a5a27421..171b1776e06 100644
--- a/chromium/cc/resources/resource_pool_unittest.cc
+++ b/chromium/cc/resources/resource_pool_unittest.cc
@@ -9,8 +9,9 @@
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "cc/test/fake_resource_provider.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/resources/resource_sizes.h"
+#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_shared_bitmap_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,14 +23,17 @@ class ResourcePoolTest : public testing::Test {
void SetUp() override {
context_provider_ = viz::TestContextProvider::Create();
context_provider_->BindToCurrentThread();
- resource_provider_ = FakeResourceProvider::CreateLayerTreeResourceProvider(
- context_provider_.get());
+ resource_provider_ = std::make_unique<viz::ClientResourceProvider>(true);
task_runner_ = base::ThreadTaskRunnerHandle::Get();
resource_pool_ = std::make_unique<ResourcePool>(
resource_provider_.get(), context_provider_.get(), task_runner_,
ResourcePool::kDefaultExpirationDelay, false);
}
+ void TearDown() override {
+ resource_provider_->ShutdownAndReleaseAllResources();
+ }
+
protected:
class StubGpuBacking : public ResourcePool::GpuBacking {
public:
@@ -54,7 +58,7 @@ class ResourcePoolTest : public testing::Test {
viz::TestSharedBitmapManager shared_bitmap_manager_;
scoped_refptr<viz::TestContextProvider> context_provider_;
- std::unique_ptr<LayerTreeResourceProvider> resource_provider_;
+ std::unique_ptr<viz::ClientResourceProvider> resource_provider_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
std::unique_ptr<ResourcePool> resource_pool_;
};
@@ -700,7 +704,6 @@ TEST_F(ResourcePoolTest, MetadataSentToDisplayCompositor) {
EXPECT_EQ(transfer[0].mailbox_holder.sync_token, sync_token);
EXPECT_EQ(transfer[0].mailbox_holder.texture_target, target);
EXPECT_EQ(transfer[0].format, format);
- EXPECT_EQ(transfer[0].buffer_format, viz::BufferFormat(format));
EXPECT_TRUE(transfer[0].read_lock_fences_enabled);
EXPECT_TRUE(transfer[0].is_overlay_candidate);
diff --git a/chromium/cc/resources/shared_bitmap_id_registrar.h b/chromium/cc/resources/shared_bitmap_id_registrar.h
index 8586a2408e7..b3533defd53 100644
--- a/chromium/cc/resources/shared_bitmap_id_registrar.h
+++ b/chromium/cc/resources/shared_bitmap_id_registrar.h
@@ -8,7 +8,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "cc/cc_export.h"
-#include "components/viz/common/quads/shared_bitmap.h"
+#include "components/viz/common/resources/shared_bitmap.h"
namespace cc {
class CrossThreadSharedBitmap;
diff --git a/chromium/cc/resources/video_resource_updater.cc b/chromium/cc/resources/video_resource_updater.cc
deleted file mode 100644
index 5004919630a..00000000000
--- a/chromium/cc/resources/video_resource_updater.cc
+++ /dev/null
@@ -1,1155 +0,0 @@
-// Copyright 2013 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/resources/video_resource_updater.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <string>
-
-#include "base/atomic_sequence_num.h"
-#include "base/bind.h"
-#include "base/bit_cast.h"
-#include "base/memory/shared_memory.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event.h"
-#include "cc/base/math_util.h"
-#include "cc/paint/skia_paint_canvas.h"
-#include "cc/resources/layer_tree_resource_provider.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/gpu/texture_allocation.h"
-#include "components/viz/common/quads/render_pass.h"
-#include "components/viz/common/quads/stream_video_draw_quad.h"
-#include "components/viz/common/quads/texture_draw_quad.h"
-#include "components/viz/common/quads/yuv_video_draw_quad.h"
-#include "components/viz/common/resources/bitmap_allocation.h"
-#include "components/viz/common/resources/resource_sizes.h"
-#include "components/viz/common/resources/shared_bitmap_reporter.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "media/base/video_frame.h"
-#include "media/renderers/paint_canvas_video_renderer.h"
-#include "media/video/half_float_maker.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
-#include "third_party/libyuv/include/libyuv.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/gl/gl_enums.h"
-#include "ui/gl/trace_util.h"
-
-namespace cc {
-namespace {
-
-// Generates process-unique IDs to use for tracing video resources.
-base::AtomicSequenceNumber g_next_video_resource_updater_id;
-
-VideoFrameResourceType ExternalResourceTypeForHardwarePlanes(
- media::VideoPixelFormat format,
- GLuint target,
- int num_textures,
- gfx::BufferFormat* buffer_format,
- bool use_stream_video_draw_quad) {
- *buffer_format = gfx::BufferFormat::RGBA_8888;
- switch (format) {
- case media::PIXEL_FORMAT_ARGB:
- case media::PIXEL_FORMAT_XRGB:
- case media::PIXEL_FORMAT_RGB32:
- case media::PIXEL_FORMAT_UYVY:
- switch (target) {
- case GL_TEXTURE_EXTERNAL_OES:
- if (use_stream_video_draw_quad)
- return VideoFrameResourceType::STREAM_TEXTURE;
- FALLTHROUGH;
- case GL_TEXTURE_2D:
- return (format == media::PIXEL_FORMAT_XRGB)
- ? VideoFrameResourceType::RGB
- : VideoFrameResourceType::RGBA_PREMULTIPLIED;
- case GL_TEXTURE_RECTANGLE_ARB:
- return VideoFrameResourceType::RGB;
- default:
- NOTREACHED();
- break;
- }
- break;
- case media::PIXEL_FORMAT_I420:
- return VideoFrameResourceType::YUV;
- case media::PIXEL_FORMAT_NV12:
- DCHECK(target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_2D ||
- target == GL_TEXTURE_RECTANGLE_ARB)
- << "Unsupported target " << gl::GLEnums::GetStringEnum(target);
- // Single plane textures can be sampled as RGB.
- if (num_textures > 1)
- return VideoFrameResourceType::YUV;
-
- *buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
- return VideoFrameResourceType::RGB;
- case media::PIXEL_FORMAT_YV12:
- case media::PIXEL_FORMAT_I422:
- case media::PIXEL_FORMAT_I444:
- case media::PIXEL_FORMAT_I420A:
- case media::PIXEL_FORMAT_NV21:
- case media::PIXEL_FORMAT_YUY2:
- case media::PIXEL_FORMAT_RGB24:
- case media::PIXEL_FORMAT_MJPEG:
- case media::PIXEL_FORMAT_MT21:
- case media::PIXEL_FORMAT_YUV420P9:
- case media::PIXEL_FORMAT_YUV422P9:
- case media::PIXEL_FORMAT_YUV444P9:
- case media::PIXEL_FORMAT_YUV420P10:
- case media::PIXEL_FORMAT_YUV422P10:
- case media::PIXEL_FORMAT_YUV444P10:
- case media::PIXEL_FORMAT_YUV420P12:
- case media::PIXEL_FORMAT_YUV422P12:
- case media::PIXEL_FORMAT_YUV444P12:
- case media::PIXEL_FORMAT_Y16:
- case media::PIXEL_FORMAT_UNKNOWN:
- break;
- }
- return VideoFrameResourceType::NONE;
-}
-
-class SyncTokenClientImpl : public media::VideoFrame::SyncTokenClient {
- public:
- SyncTokenClientImpl(gpu::gles2::GLES2Interface* gl, gpu::SyncToken sync_token)
- : gl_(gl), sync_token_(sync_token) {}
- ~SyncTokenClientImpl() override = default;
-
- void GenerateSyncToken(gpu::SyncToken* sync_token) override {
- if (sync_token_.HasData()) {
- *sync_token = sync_token_;
- } else {
- gl_->GenSyncTokenCHROMIUM(sync_token->GetData());
- }
- }
-
- void WaitSyncToken(const gpu::SyncToken& sync_token) override {
- if (sync_token.HasData()) {
- gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
- if (sync_token_.HasData() && sync_token_ != sync_token) {
- gl_->WaitSyncTokenCHROMIUM(sync_token_.GetConstData());
- sync_token_.Clear();
- }
- }
- }
-
- private:
- gpu::gles2::GLES2Interface* gl_;
- gpu::SyncToken sync_token_;
- DISALLOW_COPY_AND_ASSIGN(SyncTokenClientImpl);
-};
-
-// Sync tokens passed downstream to the compositor can be unverified.
-void GenerateCompositorSyncToken(gpu::gles2::GLES2Interface* gl,
- gpu::SyncToken* sync_token) {
- gl->GenUnverifiedSyncTokenCHROMIUM(sync_token->GetData());
-}
-
-// For frames that we receive in software format, determine the dimensions of
-// each plane in the frame.
-gfx::Size SoftwarePlaneDimension(media::VideoFrame* input_frame,
- bool software_compositor,
- size_t plane_index) {
- gfx::Size coded_size = input_frame->coded_size();
- if (software_compositor)
- return coded_size;
-
- int plane_width = media::VideoFrame::Columns(
- plane_index, input_frame->format(), coded_size.width());
- int plane_height = media::VideoFrame::Rows(plane_index, input_frame->format(),
- coded_size.height());
- return gfx::Size(plane_width, plane_height);
-}
-
-} // namespace
-
-VideoFrameExternalResources::VideoFrameExternalResources() = default;
-VideoFrameExternalResources::~VideoFrameExternalResources() = default;
-
-VideoFrameExternalResources::VideoFrameExternalResources(
- VideoFrameExternalResources&& other) = default;
-VideoFrameExternalResources& VideoFrameExternalResources::operator=(
- VideoFrameExternalResources&& other) = default;
-
-// Resource for a video plane allocated and owned by VideoResourceUpdater. There
-// can be multiple plane resources for each video frame, depending on the
-// format. These will be reused when possible.
-class VideoResourceUpdater::PlaneResource {
- public:
- PlaneResource(uint32_t plane_resource_id,
- const gfx::Size& resource_size,
- viz::ResourceFormat resource_format,
- bool is_software)
- : plane_resource_id_(plane_resource_id),
- resource_size_(resource_size),
- resource_format_(resource_format),
- is_software_(is_software) {}
- virtual ~PlaneResource() = default;
-
- // Casts |this| to SoftwarePlaneResource for software compositing.
- SoftwarePlaneResource* AsSoftware();
-
- // Casts |this| to HardwarePlaneResource for GPU compositing.
- HardwarePlaneResource* AsHardware();
-
- // Returns true if this resource matches the unique identifiers of another
- // VideoFrame resource.
- bool Matches(int unique_frame_id, size_t plane_index) {
- return has_unique_frame_id_and_plane_index_ &&
- unique_frame_id_ == unique_frame_id && plane_index_ == plane_index;
- }
-
- // Sets the unique identifiers for this resource, may only be called when
- // there is a single reference to the resource (i.e. |ref_count_| == 1).
- void SetUniqueId(int unique_frame_id, size_t plane_index) {
- DCHECK_EQ(ref_count_, 1);
- plane_index_ = plane_index;
- unique_frame_id_ = unique_frame_id;
- has_unique_frame_id_and_plane_index_ = true;
- }
-
- // Accessors for resource identifiers provided at construction time.
- uint32_t plane_resource_id() const { return plane_resource_id_; }
- const gfx::Size& resource_size() const { return resource_size_; }
- viz::ResourceFormat resource_format() const { return resource_format_; }
-
- // Various methods for managing references. See |ref_count_| for details.
- void add_ref() { ++ref_count_; }
- void remove_ref() { --ref_count_; }
- void clear_refs() { ref_count_ = 0; }
- bool has_refs() const { return ref_count_ != 0; }
-
- private:
- const uint32_t plane_resource_id_;
- const gfx::Size resource_size_;
- const viz::ResourceFormat resource_format_;
- const bool is_software_;
-
- // The number of times this resource has been imported vs number of times this
- // resource has returned.
- int ref_count_ = 0;
-
- // These two members are used for identifying the data stored in this
- // resource; they uniquely identify a media::VideoFrame plane.
- int unique_frame_id_ = 0;
- size_t plane_index_ = 0u;
- // Indicates if the above two members have been set or not.
- bool has_unique_frame_id_and_plane_index_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(PlaneResource);
-};
-
-class VideoResourceUpdater::SoftwarePlaneResource
- : public VideoResourceUpdater::PlaneResource {
- public:
- SoftwarePlaneResource(uint32_t plane_resource_id,
- const gfx::Size& size,
- viz::SharedBitmapReporter* shared_bitmap_reporter)
- : PlaneResource(plane_resource_id,
- size,
- viz::ResourceFormat::RGBA_8888,
- /*is_software=*/true),
- shared_bitmap_reporter_(shared_bitmap_reporter),
- shared_bitmap_id_(viz::SharedBitmap::GenerateId()) {
- DCHECK(shared_bitmap_reporter_);
-
- // Allocate SharedMemory and notify display compositor of the allocation.
- shared_memory_ = viz::bitmap_allocation::AllocateMappedBitmap(
- resource_size(), viz::ResourceFormat::RGBA_8888);
- mojo::ScopedSharedBufferHandle handle =
- viz::bitmap_allocation::DuplicateAndCloseMappedBitmap(
- shared_memory_.get(), resource_size(),
- viz::ResourceFormat::RGBA_8888);
- shared_bitmap_reporter_->DidAllocateSharedBitmap(std::move(handle),
- shared_bitmap_id_);
- }
- ~SoftwarePlaneResource() override {
- shared_bitmap_reporter_->DidDeleteSharedBitmap(shared_bitmap_id_);
- }
-
- const viz::SharedBitmapId& shared_bitmap_id() const {
- return shared_bitmap_id_;
- }
- void* pixels() { return shared_memory_->memory(); }
-
- // Returns a memory dump GUID consistent across processes.
- base::UnguessableToken GetSharedMemoryGuid() const {
- return shared_memory_->mapped_id();
- }
-
- private:
- viz::SharedBitmapReporter* const shared_bitmap_reporter_;
- const viz::SharedBitmapId shared_bitmap_id_;
- std::unique_ptr<base::SharedMemory> shared_memory_;
-
- DISALLOW_COPY_AND_ASSIGN(SoftwarePlaneResource);
-};
-
-class VideoResourceUpdater::HardwarePlaneResource
- : public VideoResourceUpdater::PlaneResource {
- public:
- HardwarePlaneResource(uint32_t plane_resource_id,
- const gfx::Size& size,
- viz::ResourceFormat format,
- viz::ContextProvider* context_provider,
- viz::TextureAllocation allocation)
- : PlaneResource(plane_resource_id, size, format, /*is_software=*/false),
- context_provider_(context_provider),
- mailbox_(gpu::Mailbox::Generate()),
- allocation_(std::move(allocation)) {
- DCHECK(context_provider_);
- context_provider_->ContextGL()->ProduceTextureDirectCHROMIUM(
- allocation_.texture_id, mailbox_.name);
- }
- ~HardwarePlaneResource() override {
- context_provider_->ContextGL()->DeleteTextures(1, &allocation_.texture_id);
- }
-
- const gpu::Mailbox& mailbox() const { return mailbox_; }
- GLuint texture_id() const { return allocation_.texture_id; }
- GLenum texture_target() const { return allocation_.texture_target; }
- bool overlay_candidate() const { return allocation_.overlay_candidate; }
-
- private:
- viz::ContextProvider* const context_provider_;
- const gpu::Mailbox mailbox_;
- const viz::TextureAllocation allocation_;
-
- DISALLOW_COPY_AND_ASSIGN(HardwarePlaneResource);
-};
-
-VideoResourceUpdater::SoftwarePlaneResource*
-VideoResourceUpdater::PlaneResource::AsSoftware() {
- DCHECK(is_software_);
- return static_cast<SoftwarePlaneResource*>(this);
-}
-
-VideoResourceUpdater::HardwarePlaneResource*
-VideoResourceUpdater::PlaneResource::AsHardware() {
- DCHECK(!is_software_);
- return static_cast<HardwarePlaneResource*>(this);
-}
-
-VideoResourceUpdater::VideoResourceUpdater(
- viz::ContextProvider* context_provider,
- viz::SharedBitmapReporter* shared_bitmap_reporter,
- LayerTreeResourceProvider* resource_provider,
- bool use_stream_video_draw_quad,
- bool use_gpu_memory_buffer_resources,
- bool use_r16_texture,
- int max_resource_size)
- : context_provider_(context_provider),
- shared_bitmap_reporter_(shared_bitmap_reporter),
- resource_provider_(resource_provider),
- use_stream_video_draw_quad_(use_stream_video_draw_quad),
- use_gpu_memory_buffer_resources_(use_gpu_memory_buffer_resources),
- use_r16_texture_(use_r16_texture),
- max_resource_size_(max_resource_size),
- tracing_id_(g_next_video_resource_updater_id.GetNext()),
- weak_ptr_factory_(this) {
- DCHECK(context_provider_ || shared_bitmap_reporter_);
-
- base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- this, "cc::VideoResourceUpdater", base::ThreadTaskRunnerHandle::Get());
-}
-
-VideoResourceUpdater::~VideoResourceUpdater() {
- base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
- this);
-}
-
-void VideoResourceUpdater::ObtainFrameResources(
- scoped_refptr<media::VideoFrame> video_frame) {
- VideoFrameExternalResources external_resources =
- CreateExternalResourcesFromVideoFrame(video_frame);
- frame_resource_type_ = external_resources.type;
-
- if (external_resources.type == VideoFrameResourceType::YUV) {
- frame_resource_offset_ = external_resources.offset;
- frame_resource_multiplier_ = external_resources.multiplier;
- frame_bits_per_channel_ = external_resources.bits_per_channel;
- }
-
- DCHECK_EQ(external_resources.resources.size(),
- external_resources.release_callbacks.size());
- for (size_t i = 0; i < external_resources.resources.size(); ++i) {
- viz::ResourceId resource_id = resource_provider_->ImportResource(
- external_resources.resources[i],
- viz::SingleReleaseCallback::Create(
- std::move(external_resources.release_callbacks[i])));
- frame_resources_.push_back(
- {resource_id, external_resources.resources[i].size});
- }
- TRACE_EVENT_INSTANT1("media", "VideoResourceUpdater::ObtainFrameResources",
- TRACE_EVENT_SCOPE_THREAD, "Timestamp",
- video_frame->timestamp().InMicroseconds());
-}
-
-void VideoResourceUpdater::ReleaseFrameResources() {
- for (auto& frame_resource : frame_resources_)
- resource_provider_->RemoveImportedResource(frame_resource.id);
- frame_resources_.clear();
-}
-
-void VideoResourceUpdater::AppendQuads(viz::RenderPass* render_pass,
- scoped_refptr<media::VideoFrame> frame,
- gfx::Transform transform,
- gfx::Size rotated_size,
- gfx::Rect visible_layer_rect,
- gfx::Rect clip_rect,
- bool is_clipped,
- bool contents_opaque,
- float draw_opacity,
- int sorting_context_id,
- gfx::Rect visible_quad_rect) {
- DCHECK(frame.get());
-
- viz::SharedQuadState* shared_quad_state =
- render_pass->CreateAndAppendSharedQuadState();
- gfx::Rect rotated_size_rect(rotated_size);
- shared_quad_state->SetAll(
- transform, rotated_size_rect, visible_layer_rect, clip_rect, is_clipped,
- contents_opaque, draw_opacity, SkBlendMode::kSrcOver, sorting_context_id);
-
- gfx::Rect quad_rect(rotated_size);
- gfx::Rect visible_rect = frame->visible_rect();
- bool needs_blending = !contents_opaque;
- gfx::Size coded_size = frame->coded_size();
-
- const float tex_width_scale =
- static_cast<float>(visible_rect.width()) / coded_size.width();
- const float tex_height_scale =
- static_cast<float>(visible_rect.height()) / coded_size.height();
-
- switch (frame_resource_type_) {
- case VideoFrameResourceType::YUV: {
- const gfx::Size ya_tex_size = coded_size;
-
- int u_width = media::VideoFrame::Columns(
- media::VideoFrame::kUPlane, frame->format(), coded_size.width());
- int u_height = media::VideoFrame::Rows(
- media::VideoFrame::kUPlane, frame->format(), coded_size.height());
- gfx::Size uv_tex_size(u_width, u_height);
-
- if (frame->HasTextures()) {
- if (frame->format() == media::PIXEL_FORMAT_NV12) {
- DCHECK_EQ(2u, frame_resources_.size());
- } else {
- DCHECK_EQ(media::PIXEL_FORMAT_I420, frame->format());
- DCHECK_EQ(3u,
- frame_resources_.size()); // Alpha is not supported yet.
- }
- } else {
- DCHECK_GE(frame_resources_.size(), 3u);
- DCHECK(frame_resources_.size() <= 3 ||
- ya_tex_size == media::VideoFrame::PlaneSize(
- frame->format(), media::VideoFrame::kAPlane,
- coded_size));
- }
-
- // Compute the UV sub-sampling factor based on the ratio between
- // |ya_tex_size| and |uv_tex_size|.
- float uv_subsampling_factor_x =
- static_cast<float>(ya_tex_size.width()) / uv_tex_size.width();
- float uv_subsampling_factor_y =
- static_cast<float>(ya_tex_size.height()) / uv_tex_size.height();
- gfx::RectF ya_tex_coord_rect(visible_rect);
- gfx::RectF uv_tex_coord_rect(
- visible_rect.x() / uv_subsampling_factor_x,
- visible_rect.y() / uv_subsampling_factor_y,
- visible_rect.width() / uv_subsampling_factor_x,
- visible_rect.height() / uv_subsampling_factor_y);
-
- auto* yuv_video_quad =
- render_pass->CreateAndAppendDrawQuad<viz::YUVVideoDrawQuad>();
- yuv_video_quad->SetNew(
- shared_quad_state, quad_rect, visible_quad_rect, needs_blending,
- ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size, uv_tex_size,
- frame_resources_[0].id, frame_resources_[1].id,
- frame_resources_.size() > 2 ? frame_resources_[2].id
- : frame_resources_[1].id,
- frame_resources_.size() > 3 ? frame_resources_[3].id : 0,
- frame->ColorSpace(), frame_resource_offset_,
- frame_resource_multiplier_, frame_bits_per_channel_);
- yuv_video_quad->require_overlay =
- frame->metadata()->IsTrue(media::VideoFrameMetadata::REQUIRE_OVERLAY);
- yuv_video_quad->is_protected_video =
- frame->metadata()->IsTrue(media::VideoFrameMetadata::PROTECTED_VIDEO);
-
- for (viz::ResourceId resource_id : yuv_video_quad->resources) {
- resource_provider_->ValidateResource(resource_id);
- }
- break;
- }
- case VideoFrameResourceType::RGBA:
- case VideoFrameResourceType::RGBA_PREMULTIPLIED:
- case VideoFrameResourceType::RGB: {
- DCHECK_EQ(frame_resources_.size(), 1u);
- if (frame_resources_.size() < 1u)
- break;
- bool premultiplied_alpha =
- frame_resource_type_ == VideoFrameResourceType::RGBA_PREMULTIPLIED;
- gfx::PointF uv_top_left(0.f, 0.f);
- gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
- float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
- bool flipped = false;
- bool nearest_neighbor = false;
- auto* texture_quad =
- render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
- texture_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect,
- needs_blending, frame_resources_[0].id,
- premultiplied_alpha, uv_top_left, uv_bottom_right,
- SK_ColorTRANSPARENT, opacity, flipped,
- nearest_neighbor, false);
- texture_quad->set_resource_size_in_pixels(coded_size);
- for (viz::ResourceId resource_id : texture_quad->resources) {
- resource_provider_->ValidateResource(resource_id);
- }
- break;
- }
- case VideoFrameResourceType::STREAM_TEXTURE: {
- DCHECK_EQ(frame_resources_.size(), 1u);
- if (frame_resources_.size() < 1u)
- break;
- gfx::Transform scale;
- scale.Scale(tex_width_scale, tex_height_scale);
- auto* stream_video_quad =
- render_pass->CreateAndAppendDrawQuad<viz::StreamVideoDrawQuad>();
- stream_video_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect,
- needs_blending, frame_resources_[0].id,
- frame_resources_[0].size_in_pixels, scale);
- for (viz::ResourceId resource_id : stream_video_quad->resources) {
- resource_provider_->ValidateResource(resource_id);
- }
- break;
- }
- case VideoFrameResourceType::NONE:
- NOTIMPLEMENTED();
- break;
- }
-}
-
-VideoFrameExternalResources
-VideoResourceUpdater::CreateExternalResourcesFromVideoFrame(
- scoped_refptr<media::VideoFrame> video_frame) {
- if (video_frame->format() == media::PIXEL_FORMAT_UNKNOWN)
- return VideoFrameExternalResources();
- DCHECK(video_frame->HasTextures() || video_frame->IsMappable());
- if (video_frame->HasTextures())
- return CreateForHardwarePlanes(std::move(video_frame));
- else
- return CreateForSoftwarePlanes(std::move(video_frame));
-}
-
-viz::ResourceFormat VideoResourceUpdater::YuvResourceFormat(
- int bits_per_channel) {
- DCHECK(context_provider_);
- const auto& caps = context_provider_->ContextCapabilities();
- if (caps.disable_one_component_textures)
- return viz::RGBA_8888;
- if (bits_per_channel <= 8)
- return caps.texture_rg ? viz::RED_8 : viz::LUMINANCE_8;
- if (use_r16_texture_ && caps.texture_norm16)
- return viz::R16_EXT;
- if (caps.texture_half_float_linear)
- return viz::LUMINANCE_F16;
- return viz::LUMINANCE_8;
-}
-
-VideoResourceUpdater::PlaneResource*
-VideoResourceUpdater::RecycleOrAllocateResource(
- const gfx::Size& resource_size,
- viz::ResourceFormat resource_format,
- const gfx::ColorSpace& color_space,
- int unique_id,
- int plane_index) {
- PlaneResource* recyclable_resource = nullptr;
- for (auto& resource : all_resources_) {
- // If the plane index is valid (positive, or 0, meaning all planes)
- // then we are allowed to return a referenced resource that already
- // contains the right frame data. It's safe to reuse it even if
- // resource_provider_ holds some references to it, because those
- // references are read-only.
- if (plane_index != -1 && resource->Matches(unique_id, plane_index)) {
- DCHECK(resource->resource_size() == resource_size);
- DCHECK(resource->resource_format() == resource_format);
- return resource.get();
- }
-
- // Otherwise check whether this is an unreferenced resource of the right
- // format that we can recycle. Remember it, but don't return immediately,
- // because we still want to find any reusable resources.
- const bool in_use = resource->has_refs();
-
- if (!in_use && resource->resource_size() == resource_size &&
- resource->resource_format() == resource_format) {
- recyclable_resource = resource.get();
- }
- }
-
- if (recyclable_resource)
- return recyclable_resource;
-
- // There was nothing available to reuse or recycle. Allocate a new resource.
- return AllocateResource(resource_size, resource_format, color_space);
-}
-
-VideoResourceUpdater::PlaneResource* VideoResourceUpdater::AllocateResource(
- const gfx::Size& plane_size,
- viz::ResourceFormat format,
- const gfx::ColorSpace& color_space) {
- const uint32_t plane_resource_id = next_plane_resource_id_++;
-
- if (software_compositor()) {
- DCHECK_EQ(format, viz::ResourceFormat::RGBA_8888);
-
- all_resources_.push_back(std::make_unique<SoftwarePlaneResource>(
- plane_resource_id, plane_size, shared_bitmap_reporter_));
- } else {
- // Video textures get composited into the display frame, the GPU doesn't
- // draw to them directly.
- constexpr bool kForFrameBufferAttachment = false;
-
- viz::TextureAllocation alloc = viz::TextureAllocation::MakeTextureId(
- context_provider_->ContextGL(),
- context_provider_->ContextCapabilities(), format,
- use_gpu_memory_buffer_resources_, kForFrameBufferAttachment);
- viz::TextureAllocation::AllocateStorage(
- context_provider_->ContextGL(),
- context_provider_->ContextCapabilities(), format, plane_size, alloc,
- color_space);
-
- all_resources_.push_back(std::make_unique<HardwarePlaneResource>(
- plane_resource_id, plane_size, format, context_provider_,
- std::move(alloc)));
- }
- return all_resources_.back().get();
-}
-
-void VideoResourceUpdater::CopyHardwarePlane(
- media::VideoFrame* video_frame,
- const gfx::ColorSpace& resource_color_space,
- const gpu::MailboxHolder& mailbox_holder,
- VideoFrameExternalResources* external_resources) {
- const gfx::Size output_plane_resource_size = video_frame->coded_size();
- // The copy needs to be a direct transfer of pixel data, so we use an RGBA8
- // target to avoid loss of precision or dropping any alpha component.
- constexpr viz::ResourceFormat copy_resource_format =
- viz::ResourceFormat::RGBA_8888;
-
- const int no_unique_id = 0;
- const int no_plane_index = -1; // Do not recycle referenced textures.
- PlaneResource* plane_resource = RecycleOrAllocateResource(
- output_plane_resource_size, copy_resource_format, resource_color_space,
- no_unique_id, no_plane_index);
- HardwarePlaneResource* hardware_resource = plane_resource->AsHardware();
- hardware_resource->add_ref();
-
- DCHECK_EQ(hardware_resource->texture_target(),
- static_cast<GLenum>(GL_TEXTURE_2D));
-
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
-
- gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
- uint32_t src_texture_id =
- gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name);
- gl->CopySubTextureCHROMIUM(
- src_texture_id, 0, GL_TEXTURE_2D, hardware_resource->texture_id(), 0, 0,
- 0, 0, 0, output_plane_resource_size.width(),
- output_plane_resource_size.height(), false, false, false);
- gl->DeleteTextures(1, &src_texture_id);
-
- // Pass an empty sync token to force generation of a new sync token.
- SyncTokenClientImpl client(gl, gpu::SyncToken());
- gpu::SyncToken sync_token = video_frame->UpdateReleaseSyncToken(&client);
-
- auto transferable_resource = viz::TransferableResource::MakeGL(
- hardware_resource->mailbox(), GL_LINEAR, GL_TEXTURE_2D, sync_token);
- transferable_resource.color_space = resource_color_space;
- transferable_resource.format = copy_resource_format;
- transferable_resource.buffer_format = viz::BufferFormat(copy_resource_format);
- external_resources->resources.push_back(std::move(transferable_resource));
-
- external_resources->release_callbacks.push_back(base::BindOnce(
- &VideoResourceUpdater::RecycleResource, weak_ptr_factory_.GetWeakPtr(),
- hardware_resource->plane_resource_id()));
-}
-
-VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
- scoped_refptr<media::VideoFrame> video_frame) {
- TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForHardwarePlanes");
- DCHECK(video_frame->HasTextures());
- if (!context_provider_)
- return VideoFrameExternalResources();
-
- VideoFrameExternalResources external_resources;
- gfx::ColorSpace resource_color_space = video_frame->ColorSpace();
-
- bool copy_required =
- video_frame->metadata()->IsTrue(media::VideoFrameMetadata::COPY_REQUIRED);
-
- GLuint target = video_frame->mailbox_holder(0).texture_target;
- // If |copy_required| then we will copy into a GL_TEXTURE_2D target.
- if (copy_required)
- target = GL_TEXTURE_2D;
-
- gfx::BufferFormat buffer_format;
- external_resources.type = ExternalResourceTypeForHardwarePlanes(
- video_frame->format(), target, video_frame->NumTextures(), &buffer_format,
- use_stream_video_draw_quad_);
- if (external_resources.type == VideoFrameResourceType::NONE) {
- DLOG(ERROR) << "Unsupported Texture format"
- << media::VideoPixelFormatToString(video_frame->format());
- return external_resources;
- }
- if (external_resources.type == VideoFrameResourceType::RGB ||
- external_resources.type == VideoFrameResourceType::RGBA ||
- external_resources.type == VideoFrameResourceType::RGBA_PREMULTIPLIED) {
- resource_color_space = resource_color_space.GetAsFullRangeRGB();
- }
-
- const size_t num_textures = video_frame->NumTextures();
- for (size_t i = 0; i < num_textures; ++i) {
- const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i);
- if (mailbox_holder.mailbox.IsZero())
- break;
-
- if (copy_required) {
- CopyHardwarePlane(video_frame.get(), resource_color_space, mailbox_holder,
- &external_resources);
- } else {
- auto transfer_resource = viz::TransferableResource::MakeGLOverlay(
- mailbox_holder.mailbox, GL_LINEAR, mailbox_holder.texture_target,
- mailbox_holder.sync_token, video_frame->coded_size(),
- video_frame->metadata()->IsTrue(
- media::VideoFrameMetadata::ALLOW_OVERLAY));
- transfer_resource.color_space = resource_color_space;
- transfer_resource.read_lock_fences_enabled =
- video_frame->metadata()->IsTrue(
- media::VideoFrameMetadata::READ_LOCK_FENCES_ENABLED);
- transfer_resource.buffer_format = buffer_format;
-#if defined(OS_ANDROID)
- transfer_resource.is_backed_by_surface_texture =
- video_frame->metadata()->IsTrue(
- media::VideoFrameMetadata::TEXTURE_OWNER);
- transfer_resource.wants_promotion_hint = video_frame->metadata()->IsTrue(
- media::VideoFrameMetadata::WANTS_PROMOTION_HINT);
-#endif
- external_resources.resources.push_back(std::move(transfer_resource));
- external_resources.release_callbacks.push_back(
- base::BindOnce(&VideoResourceUpdater::ReturnTexture,
- weak_ptr_factory_.GetWeakPtr(), video_frame));
- }
- }
- return external_resources;
-}
-
-VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
- scoped_refptr<media::VideoFrame> video_frame) {
- TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes");
- const media::VideoPixelFormat input_frame_format = video_frame->format();
-
- size_t bits_per_channel = video_frame->BitDepth();
-
- // Only YUV and Y16 software video frames are supported.
- DCHECK(media::IsYuvPlanar(input_frame_format) ||
- input_frame_format == media::PIXEL_FORMAT_Y16);
-
- viz::ResourceFormat output_resource_format;
- gfx::ColorSpace output_color_space = video_frame->ColorSpace();
- if (input_frame_format == media::PIXEL_FORMAT_Y16) {
- // Unable to display directly as yuv planes so convert it to RGBA for
- // compositing.
- output_resource_format = viz::RGBA_8888;
- output_color_space = output_color_space.GetAsFullRangeRGB();
- } else if (!software_compositor()) {
- // Can be composited directly from yuv planes.
- output_resource_format = YuvResourceFormat(bits_per_channel);
- }
-
- // If GPU compositing is enabled, but the output resource format
- // returned by the resource provider is viz::RGBA_8888, then a GPU driver
- // bug workaround requires that YUV frames must be converted to RGB
- // before texture upload.
- bool texture_needs_rgb_conversion =
- !software_compositor() &&
- output_resource_format == viz::ResourceFormat::RGBA_8888;
-
- size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format);
-
- // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB
- // conversion here. That involves an extra copy of each frame to a bitmap.
- // Obviously, this is suboptimal and should be addressed once ubercompositor
- // starts shaping up.
- if (software_compositor() || texture_needs_rgb_conversion) {
- output_resource_format = viz::RGBA_8888;
- output_plane_count = 1;
- bits_per_channel = 8;
-
- // The YUV to RGB conversion will be performed when we convert
- // from single-channel textures to an RGBA texture via
- // ConvertVideoFrameToRGBPixels below.
- output_color_space = output_color_space.GetAsFullRangeRGB();
- }
-
- std::vector<gfx::Size> outplane_plane_sizes;
- outplane_plane_sizes.reserve(output_plane_count);
- for (size_t i = 0; i < output_plane_count; ++i) {
- outplane_plane_sizes.push_back(
- SoftwarePlaneDimension(video_frame.get(), software_compositor(), i));
- const gfx::Size& output_plane_resource_size = outplane_plane_sizes.back();
- if (output_plane_resource_size.IsEmpty() ||
- output_plane_resource_size.width() > max_resource_size_ ||
- output_plane_resource_size.height() > max_resource_size_) {
- // This output plane has invalid geometry so return an empty external
- // resources.
- return VideoFrameExternalResources();
- }
- }
-
- // Delete recycled resources that are the wrong format or wrong size.
- auto can_delete_resource_fn =
- [output_resource_format,
- &outplane_plane_sizes](const std::unique_ptr<PlaneResource>& resource) {
- // Resources that are still being used can't be deleted.
- if (resource->has_refs())
- return false;
-
- return resource->resource_format() != output_resource_format ||
- !base::ContainsValue(outplane_plane_sizes,
- resource->resource_size());
- };
- base::EraseIf(all_resources_, can_delete_resource_fn);
-
- // Recycle or allocate resources for each video plane.
- std::vector<PlaneResource*> plane_resources;
- plane_resources.reserve(output_plane_count);
- for (size_t i = 0; i < output_plane_count; ++i) {
- plane_resources.push_back(RecycleOrAllocateResource(
- outplane_plane_sizes[i], output_resource_format, output_color_space,
- video_frame->unique_id(), i));
- plane_resources.back()->add_ref();
- }
-
- VideoFrameExternalResources external_resources;
-
- external_resources.bits_per_channel = bits_per_channel;
-
- if (software_compositor() || texture_needs_rgb_conversion) {
- DCHECK_EQ(plane_resources.size(), 1u);
- PlaneResource* plane_resource = plane_resources[0];
- DCHECK_EQ(plane_resource->resource_format(), viz::RGBA_8888);
-
- if (!plane_resource->Matches(video_frame->unique_id(), 0)) {
- // We need to transfer data from |video_frame| to the plane resource.
- if (software_compositor()) {
- if (!video_renderer_)
- video_renderer_ = std::make_unique<media::PaintCanvasVideoRenderer>();
-
- SoftwarePlaneResource* software_resource = plane_resource->AsSoftware();
-
- // We know the format is RGBA_8888 from check above.
- SkImageInfo info = SkImageInfo::MakeN32Premul(
- gfx::SizeToSkISize(software_resource->resource_size()));
-
- SkBitmap sk_bitmap;
- sk_bitmap.installPixels(info, software_resource->pixels(),
- info.minRowBytes());
- SkiaPaintCanvas canvas(sk_bitmap);
-
- // This is software path, so canvas and video_frame are always backed
- // by software.
- video_renderer_->Copy(video_frame, &canvas, media::Context3D());
- } else {
- HardwarePlaneResource* hardware_resource = plane_resource->AsHardware();
- size_t bytes_per_row = viz::ResourceSizes::CheckedWidthInBytes<size_t>(
- video_frame->coded_size().width(), viz::ResourceFormat::RGBA_8888);
- size_t needed_size = bytes_per_row * video_frame->coded_size().height();
- if (upload_pixels_.size() < needed_size) {
- // Clear before resizing to avoid memcpy.
- upload_pixels_.clear();
- upload_pixels_.resize(needed_size);
- }
-
- media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
- video_frame.get(), &upload_pixels_[0], bytes_per_row);
-
- // Copy pixels into texture.
- auto* gl = context_provider_->ContextGL();
- gl->BindTexture(hardware_resource->texture_target(),
- hardware_resource->texture_id());
- const gfx::Size& plane_size = hardware_resource->resource_size();
- gl->TexSubImage2D(
- hardware_resource->texture_target(), 0, 0, 0, plane_size.width(),
- plane_size.height(), GLDataFormat(viz::ResourceFormat::RGBA_8888),
- GLDataType(viz::ResourceFormat::RGBA_8888), &upload_pixels_[0]);
- }
- plane_resource->SetUniqueId(video_frame->unique_id(), 0);
- }
-
- viz::TransferableResource transferable_resource;
- if (software_compositor()) {
- SoftwarePlaneResource* software_resource = plane_resource->AsSoftware();
- external_resources.type = VideoFrameResourceType::RGBA_PREMULTIPLIED;
- transferable_resource = viz::TransferableResource::MakeSoftware(
- software_resource->shared_bitmap_id(),
- software_resource->resource_size(),
- plane_resource->resource_format());
- } else {
- HardwarePlaneResource* hardware_resource = plane_resource->AsHardware();
- external_resources.type = VideoFrameResourceType::RGBA;
- gpu::SyncToken sync_token;
- GenerateCompositorSyncToken(context_provider_->ContextGL(), &sync_token);
- transferable_resource = viz::TransferableResource::MakeGLOverlay(
- hardware_resource->mailbox(), GL_LINEAR,
- hardware_resource->texture_target(), sync_token,
- hardware_resource->resource_size(),
- hardware_resource->overlay_candidate());
- }
-
- transferable_resource.color_space = output_color_space;
- transferable_resource.format = viz::ResourceFormat::RGBA_8888;
- transferable_resource.buffer_format =
- viz::BufferFormat(viz::ResourceFormat::RGBA_8888);
- external_resources.resources.push_back(std::move(transferable_resource));
- external_resources.release_callbacks.push_back(base::BindOnce(
- &VideoResourceUpdater::RecycleResource, weak_ptr_factory_.GetWeakPtr(),
- plane_resource->plane_resource_id()));
-
- return external_resources;
- }
-
- const viz::ResourceFormat yuv_resource_format =
- YuvResourceFormat(bits_per_channel);
- DCHECK(yuv_resource_format == viz::LUMINANCE_F16 ||
- yuv_resource_format == viz::R16_EXT ||
- yuv_resource_format == viz::LUMINANCE_8 ||
- yuv_resource_format == viz::RED_8)
- << yuv_resource_format;
-
- std::unique_ptr<media::HalfFloatMaker> half_float_maker;
- if (yuv_resource_format == viz::LUMINANCE_F16) {
- half_float_maker =
- media::HalfFloatMaker::NewHalfFloatMaker(bits_per_channel);
- external_resources.offset = half_float_maker->Offset();
- external_resources.multiplier = half_float_maker->Multiplier();
- } else if (yuv_resource_format == viz::R16_EXT) {
- external_resources.multiplier = 65535.0f / ((1 << bits_per_channel) - 1);
- external_resources.offset = 0;
- }
-
- // We need to transfer data from |video_frame| to the plane resources.
- for (size_t i = 0; i < plane_resources.size(); ++i) {
- HardwarePlaneResource* plane_resource = plane_resources[i]->AsHardware();
-
- // Skip the transfer if this |video_frame|'s plane has been processed.
- if (plane_resource->Matches(video_frame->unique_id(), i))
- continue;
-
- const viz::ResourceFormat plane_resource_format =
- plane_resource->resource_format();
- DCHECK_EQ(plane_resource_format, yuv_resource_format);
-
- // TODO(hubbe): Move upload code to media/.
- // TODO(reveman): Can use GpuMemoryBuffers here to improve performance.
-
- // |video_stride_bytes| is the width of the |video_frame| we are uploading
- // (including non-frame data to fill in the stride).
- const int video_stride_bytes = video_frame->stride(i);
-
- // |resource_size_pixels| is the size of the destination resource.
- const gfx::Size resource_size_pixels = plane_resource->resource_size();
-
- const size_t bytes_per_row =
- viz::ResourceSizes::CheckedWidthInBytes<size_t>(
- resource_size_pixels.width(), plane_resource_format);
- // Use 4-byte row alignment (OpenGL default) for upload performance.
- // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
- const size_t upload_image_stride =
- MathUtil::CheckedRoundUp<size_t>(bytes_per_row, 4u);
-
- const size_t resource_bit_depth =
- static_cast<size_t>(viz::BitsPerPixel(plane_resource_format));
-
- // Data downshifting is needed if the resource bit depth is not enough.
- const bool needs_bit_downshifting = bits_per_channel > resource_bit_depth;
-
- // A copy to adjust strides is needed if those are different and both source
- // and destination have the same bit depth.
- const bool needs_stride_adaptation =
- (bits_per_channel == resource_bit_depth) &&
- (upload_image_stride != static_cast<size_t>(video_stride_bytes));
-
- // We need to convert the incoming data if we're transferring to half float,
- // if the need a bit downshift or if the strides need to be reconciled.
- const bool needs_conversion = plane_resource_format == viz::LUMINANCE_F16 ||
- needs_bit_downshifting ||
- needs_stride_adaptation;
-
- const uint8_t* pixels;
- if (!needs_conversion) {
- pixels = video_frame->data(i);
- } else {
- // Avoid malloc for each frame/plane if possible.
- const size_t needed_size =
- upload_image_stride * resource_size_pixels.height();
- if (upload_pixels_.size() < needed_size) {
- // Clear before resizing to avoid memcpy.
- upload_pixels_.clear();
- upload_pixels_.resize(needed_size);
- }
-
- if (plane_resource_format == viz::LUMINANCE_F16) {
- for (int row = 0; row < resource_size_pixels.height(); ++row) {
- uint16_t* dst = reinterpret_cast<uint16_t*>(
- &upload_pixels_[upload_image_stride * row]);
- const uint16_t* src = reinterpret_cast<uint16_t*>(
- video_frame->data(i) + (video_stride_bytes * row));
- half_float_maker->MakeHalfFloats(src, bytes_per_row / 2, dst);
- }
- } else if (needs_bit_downshifting) {
- DCHECK(plane_resource_format == viz::LUMINANCE_8 ||
- plane_resource_format == viz::RED_8);
- const int scale = 0x10000 >> (bits_per_channel - 8);
- libyuv::Convert16To8Plane(
- reinterpret_cast<uint16_t*>(video_frame->data(i)),
- video_stride_bytes / 2, upload_pixels_.data(), upload_image_stride,
- scale, bytes_per_row, resource_size_pixels.height());
- } else {
- // Make a copy to reconcile stride, size and format being equal.
- DCHECK(needs_stride_adaptation);
- DCHECK(plane_resource_format == viz::LUMINANCE_8 ||
- plane_resource_format == viz::RED_8);
- libyuv::CopyPlane(video_frame->data(i), video_stride_bytes,
- upload_pixels_.data(), upload_image_stride,
- resource_size_pixels.width(),
- resource_size_pixels.height());
- }
-
- pixels = &upload_pixels_[0];
- }
-
- // Copy pixels into texture. TexSubImage2D() is applicable because
- // |yuv_resource_format| is LUMINANCE_F16, R16_EXT, LUMINANCE_8 or RED_8.
- auto* gl = context_provider_->ContextGL();
- gl->BindTexture(plane_resource->texture_target(),
- plane_resource->texture_id());
- gl->TexSubImage2D(
- plane_resource->texture_target(), 0, 0, 0, resource_size_pixels.width(),
- resource_size_pixels.height(), GLDataFormat(plane_resource_format),
- GLDataType(plane_resource_format), pixels);
-
- plane_resource->SetUniqueId(video_frame->unique_id(), i);
- }
-
- // Set the sync token otherwise resource is assumed to be synchronized.
- gpu::SyncToken sync_token;
- GenerateCompositorSyncToken(context_provider_->ContextGL(), &sync_token);
-
- for (size_t i = 0; i < plane_resources.size(); ++i) {
- HardwarePlaneResource* plane_resource = plane_resources[i]->AsHardware();
- auto transferable_resource = viz::TransferableResource::MakeGLOverlay(
- plane_resource->mailbox(), GL_LINEAR, plane_resource->texture_target(),
- sync_token, plane_resource->resource_size(),
- plane_resource->overlay_candidate());
- transferable_resource.color_space = output_color_space;
- transferable_resource.format = output_resource_format;
- transferable_resource.buffer_format =
- viz::BufferFormat(output_resource_format);
- external_resources.resources.push_back(std::move(transferable_resource));
- external_resources.release_callbacks.push_back(base::BindOnce(
- &VideoResourceUpdater::RecycleResource, weak_ptr_factory_.GetWeakPtr(),
- plane_resource->plane_resource_id()));
- }
-
- external_resources.type = VideoFrameResourceType::YUV;
- return external_resources;
-}
-
-void VideoResourceUpdater::ReturnTexture(
- const scoped_refptr<media::VideoFrame>& video_frame,
- const gpu::SyncToken& sync_token,
- bool lost_resource) {
- // TODO(dshwang): Forward to the decoder as a lost resource.
- if (lost_resource)
- return;
-
- // The video frame will insert a wait on the previous release sync token.
- SyncTokenClientImpl client(context_provider_->ContextGL(), sync_token);
- video_frame->UpdateReleaseSyncToken(&client);
-}
-
-void VideoResourceUpdater::RecycleResource(uint32_t plane_resource_id,
- const gpu::SyncToken& sync_token,
- bool lost_resource) {
- auto matches_id_fn =
- [plane_resource_id](const std::unique_ptr<PlaneResource>& resource) {
- return resource->plane_resource_id() == plane_resource_id;
- };
- auto resource_it =
- std::find_if(all_resources_.begin(), all_resources_.end(), matches_id_fn);
- if (resource_it == all_resources_.end())
- return;
-
- if (context_provider_ && sync_token.HasData()) {
- context_provider_->ContextGL()->WaitSyncTokenCHROMIUM(
- sync_token.GetConstData());
- }
-
- if (lost_resource) {
- all_resources_.erase(resource_it);
- } else {
- (*resource_it)->remove_ref();
- }
-}
-
-bool VideoResourceUpdater::OnMemoryDump(
- const base::trace_event::MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd) {
- for (auto& resource : all_resources_) {
- std::string dump_name =
- base::StringPrintf("cc/video_memory/updater_%d/resource_%d",
- tracing_id_, resource->plane_resource_id());
- base::trace_event::MemoryAllocatorDump* dump =
- pmd->CreateAllocatorDump(dump_name);
-
- const uint64_t total_bytes =
- viz::ResourceSizes::UncheckedSizeInBytesAligned<uint64_t>(
- resource->resource_size(), resource->resource_format());
- dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
- base::trace_event::MemoryAllocatorDump::kUnitsBytes,
- total_bytes);
-
- // The importance value assigned to the GUID here must be greater than the
- // importance value assigned elsewhere so that resource ownership is
- // attributed to VideoResourceUpdater.
- constexpr int kImportance = 2;
-
- // Resources are shared across processes and require a shared GUID to
- // prevent double counting the memory.
- if (software_compositor()) {
- base::UnguessableToken shm_guid =
- resource->AsSoftware()->GetSharedMemoryGuid();
- pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), shm_guid, kImportance);
- } else {
- base::trace_event::MemoryAllocatorDumpGuid guid =
- gl::GetGLTextureClientGUIDForTracing(
- context_provider_->ContextSupport()->ShareGroupTracingGUID(),
- resource->AsHardware()->texture_id());
- pmd->CreateSharedGlobalAllocatorDump(guid);
- pmd->AddOwnershipEdge(dump->guid(), guid, kImportance);
- }
- }
-
- return true;
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/video_resource_updater.h b/chromium/cc/resources/video_resource_updater.h
deleted file mode 100644
index 0b3f651bed6..00000000000
--- a/chromium/cc/resources/video_resource_updater.h
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright 2013 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_RESOURCES_VIDEO_RESOURCE_UPDATER_H_
-#define CC_RESOURCES_VIDEO_RESOURCE_UPDATER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <list>
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "cc/cc_export.h"
-#include "components/viz/common/resources/release_callback.h"
-#include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_id.h"
-#include "components/viz/common/resources/transferable_resource.h"
-#include "ui/gfx/buffer_types.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace media {
-class PaintCanvasVideoRenderer;
-class VideoFrame;
-}
-
-namespace gfx {
-class Rect;
-class Transform;
-} // namespace gfx
-
-namespace viz {
-class ContextProvider;
-class RenderPass;
-class SharedBitmapReporter;
-}
-
-namespace cc {
-class LayerTreeResourceProvider;
-
-// Specifies what type of data is contained in the mailboxes, as well as how
-// many mailboxes will be present.
-enum class VideoFrameResourceType {
- NONE,
- YUV,
- RGB,
- RGBA_PREMULTIPLIED,
- RGBA,
- STREAM_TEXTURE,
-};
-
-class CC_EXPORT VideoFrameExternalResources {
- public:
- VideoFrameResourceType type = VideoFrameResourceType::NONE;
- std::vector<viz::TransferableResource> resources;
- std::vector<viz::ReleaseCallback> release_callbacks;
-
- // Used by hardware textures which do not return values in the 0-1 range.
- // After a lookup, subtract offset and multiply by multiplier.
- float offset = 0.f;
- float multiplier = 1.f;
- uint32_t bits_per_channel = 8;
-
- VideoFrameExternalResources();
- VideoFrameExternalResources(VideoFrameExternalResources&& other);
- VideoFrameExternalResources& operator=(VideoFrameExternalResources&& other);
- ~VideoFrameExternalResources();
-};
-
-// VideoResourceUpdater is used by the video system to produce frame content as
-// resources consumable by the compositor.
-class CC_EXPORT VideoResourceUpdater
- : public base::trace_event::MemoryDumpProvider {
- public:
- // For GPU compositing |context_provider| should be provided and for software
- // compositing |shared_bitmap_reporter| should be provided. If there is a
- // non-null |context_provider| we assume GPU compositing.
- VideoResourceUpdater(viz::ContextProvider* context_provider,
- viz::SharedBitmapReporter* shared_bitmap_reporter,
- LayerTreeResourceProvider* resource_provider,
- bool use_stream_video_draw_quad,
- bool use_gpu_memory_buffer_resources,
- bool use_r16_texture,
- int max_resource_size);
-
- ~VideoResourceUpdater() override;
-
- // For each CompositorFrame the following sequence is expected:
- // 1. ObtainFrameResources(): Import resources for the next video frame with
- // LayerTreeResourceProvider. This will reuse existing GPU or SharedMemory
- // buffers if possible, otherwise it will allocate new ones.
- // 2. AppendQuads(): Add DrawQuads to CompositorFrame for video.
- // 3. ReleaseFrameResources(): After the CompositorFrame has been submitted,
- // remove imported resources from LayerTreeResourceProvider.
- void ObtainFrameResources(scoped_refptr<media::VideoFrame> video_frame);
- void ReleaseFrameResources();
- void AppendQuads(viz::RenderPass* render_pass,
- scoped_refptr<media::VideoFrame> frame,
- gfx::Transform transform,
- gfx::Size rotated_size,
- gfx::Rect visible_layer_rect,
- gfx::Rect clip_rect,
- bool is_clipped,
- bool context_opaque,
- float draw_opacity,
- int sorting_context_id,
- gfx::Rect visible_quad_rect);
-
- // TODO(kylechar): This is only public for testing, make private.
- VideoFrameExternalResources CreateExternalResourcesFromVideoFrame(
- scoped_refptr<media::VideoFrame> video_frame);
-
- viz::ResourceFormat YuvResourceFormat(int bits_per_channel);
-
- private:
- class PlaneResource;
- class HardwarePlaneResource;
- class SoftwarePlaneResource;
-
- // A resource that will be embedded in a DrawQuad in the next CompositorFrame.
- // Each video plane will correspond to one FrameResource.
- struct FrameResource {
- viz::ResourceId id;
- gfx::Size size_in_pixels;
- };
-
- bool software_compositor() const { return context_provider_ == nullptr; }
-
- // Obtain a resource of the right format by either recycling an
- // unreferenced but appropriately formatted resource, or by
- // allocating a new resource.
- // Additionally, if the |unique_id| and |plane_index| match, then
- // it is assumed that the resource has the right data already and will only be
- // used for reading, and so is returned even if it is still referenced.
- // Passing -1 for |plane_index| avoids returning referenced
- // resources.
- PlaneResource* RecycleOrAllocateResource(const gfx::Size& resource_size,
- viz::ResourceFormat resource_format,
- const gfx::ColorSpace& color_space,
- int unique_id,
- int plane_index);
- PlaneResource* AllocateResource(const gfx::Size& plane_size,
- viz::ResourceFormat format,
- const gfx::ColorSpace& color_space);
-
- // Create a copy of a texture-backed source video frame in a new GL_TEXTURE_2D
- // texture. This is used when there are multiple GPU threads (Android WebView)
- // and the source video frame texture can't be used on the output GL context.
- // https://crbug.com/582170
- void CopyHardwarePlane(media::VideoFrame* video_frame,
- const gfx::ColorSpace& resource_color_space,
- const gpu::MailboxHolder& mailbox_holder,
- VideoFrameExternalResources* external_resources);
-
- // Get resources ready to be appended into DrawQuads. This is used for GPU
- // compositing most of the time, except for the cases mentioned in
- // CreateForSoftwarePlanes().
- VideoFrameExternalResources CreateForHardwarePlanes(
- scoped_refptr<media::VideoFrame> video_frame);
-
- // Get resources ready to be appended into DrawQuads. This is always used for
- // software compositing. This is also used for GPU compositing when the input
- // video frame has no textures.
- VideoFrameExternalResources CreateForSoftwarePlanes(
- scoped_refptr<media::VideoFrame> video_frame);
-
- void RecycleResource(uint32_t plane_resource_id,
- const gpu::SyncToken& sync_token,
- bool lost_resource);
- void ReturnTexture(const scoped_refptr<media::VideoFrame>& video_frame,
- const gpu::SyncToken& sync_token,
- bool lost_resource);
-
- // base::trace_event::MemoryDumpProvider implementation.
- bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd) override;
-
- viz::ContextProvider* const context_provider_;
- viz::SharedBitmapReporter* const shared_bitmap_reporter_;
- LayerTreeResourceProvider* const resource_provider_;
- const bool use_stream_video_draw_quad_;
- const bool use_gpu_memory_buffer_resources_;
- // TODO(crbug.com/759456): Remove after r16 is used without the flag.
- const bool use_r16_texture_;
- const int max_resource_size_;
- const int tracing_id_;
- std::unique_ptr<media::PaintCanvasVideoRenderer> video_renderer_;
- uint32_t next_plane_resource_id_ = 1;
-
- // Temporary pixel buffer when converting between formats.
- std::vector<uint8_t> upload_pixels_;
-
- VideoFrameResourceType frame_resource_type_;
-
- float frame_resource_offset_;
- float frame_resource_multiplier_;
- uint32_t frame_bits_per_channel_;
-
- // Resources that will be placed into quads by the next call to
- // AppendDrawQuads().
- std::vector<FrameResource> frame_resources_;
-
- // Resources allocated by VideoResourceUpdater. Used to recycle resources so
- // we can reduce the number of allocations and data transfers.
- std::vector<std::unique_ptr<PlaneResource>> all_resources_;
-
- base::WeakPtrFactory<VideoResourceUpdater> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(VideoResourceUpdater);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_VIDEO_RESOURCE_UPDATER_H_
diff --git a/chromium/cc/resources/video_resource_updater_unittest.cc b/chromium/cc/resources/video_resource_updater_unittest.cc
deleted file mode 100644
index a26069cdd48..00000000000
--- a/chromium/cc/resources/video_resource_updater_unittest.cc
+++ /dev/null
@@ -1,737 +0,0 @@
-// Copyright 2013 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/resources/video_resource_updater.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "cc/resources/layer_tree_resource_provider.h"
-#include "cc/test/fake_layer_tree_frame_sink.h"
-#include "cc/test/fake_output_surface_client.h"
-#include "cc/test/fake_resource_provider.h"
-#include "components/viz/test/fake_output_surface.h"
-#include "components/viz/test/test_gles2_interface.h"
-#include "components/viz/test/test_web_graphics_context_3d.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "media/base/video_frame.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-namespace {
-
-class UploadCounterGLES2Interface : public viz::TestGLES2Interface {
- public:
- void TexSubImage2D(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- const void* pixels) override {
- ++upload_count_;
- }
-
- void TexStorage2DEXT(GLenum target,
- GLint levels,
- GLuint internalformat,
- GLint width,
- GLint height) override {}
-
- void GenTextures(GLsizei n, GLuint* textures) override {
- created_texture_count_ += n;
- viz::TestGLES2Interface::GenTextures(n, textures);
- }
-
- void DeleteTextures(GLsizei n, const GLuint* textures) override {
- created_texture_count_ -= n;
- viz::TestGLES2Interface::DeleteTextures(n, textures);
- }
-
- int UploadCount() { return upload_count_; }
- void ResetUploadCount() { upload_count_ = 0; }
-
- int TextureCreationCount() { return created_texture_count_; }
- void ResetTextureCreationCount() { created_texture_count_ = 0; }
-
- private:
- int upload_count_;
- int created_texture_count_;
-};
-
-class VideoResourceUpdaterTest : public testing::Test {
- protected:
- VideoResourceUpdaterTest() {
- std::unique_ptr<UploadCounterGLES2Interface> gl(
- new UploadCounterGLES2Interface());
-
- gl_ = gl.get();
- gl_->set_support_texture_storage(true);
-
- context_provider_ = viz::TestContextProvider::Create(std::move(gl));
- context_provider_->BindToCurrentThread();
- }
-
- // testing::Test implementation.
- void SetUp() override {
- testing::Test::SetUp();
- layer_tree_frame_sink_software_ = FakeLayerTreeFrameSink::CreateSoftware();
- resource_provider3d_ =
- FakeResourceProvider::CreateLayerTreeResourceProvider(
- context_provider_.get());
- resource_provider_software_ =
- FakeResourceProvider::CreateLayerTreeResourceProvider(nullptr);
- }
-
- std::unique_ptr<VideoResourceUpdater> CreateUpdaterForHardware(
- bool use_stream_video_draw_quad = false) {
- return std::make_unique<VideoResourceUpdater>(
- context_provider_.get(), nullptr, resource_provider3d_.get(),
- use_stream_video_draw_quad, /*use_gpu_memory_buffer_resources=*/false,
- /*use_r16_texture=*/use_r16_texture_, /*max_resource_size=*/10000);
- }
-
- std::unique_ptr<VideoResourceUpdater> CreateUpdaterForSoftware() {
- return std::make_unique<VideoResourceUpdater>(
- nullptr, layer_tree_frame_sink_software_.get(),
- resource_provider_software_.get(),
- /*use_stream_video_draw_quad=*/false,
- /*use_gpu_memory_buffer_resources=*/false,
- /*use_r16_texture=*/false,
- /*max_resource_size=*/10000);
- }
-
- // Note that the number of pixels needed for |size| must be less than or equal
- // to the number of pixels needed for size of 100x100.
- scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame(
- const gfx::Size& size = gfx::Size(10, 10)) {
- constexpr int kMaxDimension = 100;
- static uint8_t y_data[kMaxDimension * kMaxDimension] = {0};
- static uint8_t u_data[kMaxDimension * kMaxDimension / 2] = {0};
- static uint8_t v_data[kMaxDimension * kMaxDimension / 2] = {0};
-
- CHECK_LE(size.width() * size.height(), kMaxDimension * kMaxDimension);
-
- scoped_refptr<media::VideoFrame> video_frame =
- media::VideoFrame::WrapExternalYuvData(
- media::PIXEL_FORMAT_I422, // format
- size, // coded_size
- gfx::Rect(size), // visible_rect
- size, // natural_size
- size.width(), // y_stride
- size.width() / 2, // u_stride
- size.width() / 2, // v_stride
- y_data, // y_data
- u_data, // u_data
- v_data, // v_data
- base::TimeDelta()); // timestamp
- EXPECT_TRUE(video_frame);
- return video_frame;
- }
-
- scoped_refptr<media::VideoFrame> CreateWonkyTestYUVVideoFrame() {
- const int kDimension = 10;
- const int kYWidth = kDimension + 5;
- const int kUWidth = (kYWidth + 1) / 2 + 200;
- const int kVWidth = (kYWidth + 1) / 2 + 1;
- static uint8_t y_data[kYWidth * kDimension] = {0};
- static uint8_t u_data[kUWidth * kDimension] = {0};
- static uint8_t v_data[kVWidth * kDimension] = {0};
-
- scoped_refptr<media::VideoFrame> video_frame =
- media::VideoFrame::WrapExternalYuvData(
- media::PIXEL_FORMAT_I422, // format
- gfx::Size(kYWidth, kDimension), // coded_size
- gfx::Rect(2, 0, kDimension, kDimension), // visible_rect
- gfx::Size(kDimension, kDimension), // natural_size
- -kYWidth, // y_stride (negative)
- kUWidth, // u_stride
- kVWidth, // v_stride
- y_data + kYWidth * (kDimension - 1), // y_data
- u_data, // u_data
- v_data, // v_data
- base::TimeDelta()); // timestamp
- EXPECT_TRUE(video_frame);
- return video_frame;
- }
-
- scoped_refptr<media::VideoFrame> CreateTestHighBitFrame() {
- const int kDimension = 10;
- gfx::Size size(kDimension, kDimension);
-
- scoped_refptr<media::VideoFrame> video_frame(media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_YUV420P10, size, gfx::Rect(size), size,
- base::TimeDelta()));
- EXPECT_TRUE(video_frame);
- return video_frame;
- }
-
- void SetReleaseSyncToken(const gpu::SyncToken& sync_token) {
- release_sync_token_ = sync_token;
- }
-
- scoped_refptr<media::VideoFrame> CreateTestHardwareVideoFrame(
- media::VideoPixelFormat format,
- unsigned target) {
- const int kDimension = 10;
- gfx::Size size(kDimension, kDimension);
-
- gpu::Mailbox mailbox;
- mailbox.name[0] = 51;
-
- gpu::MailboxHolder mailbox_holders[media::VideoFrame::kMaxPlanes] = {
- gpu::MailboxHolder(mailbox, kMailboxSyncToken, target)};
- scoped_refptr<media::VideoFrame> video_frame =
- media::VideoFrame::WrapNativeTextures(
- format, mailbox_holders,
- base::Bind(&VideoResourceUpdaterTest::SetReleaseSyncToken,
- base::Unretained(this)),
- size, // coded_size
- gfx::Rect(size), // visible_rect
- size, // natural_size
- base::TimeDelta()); // timestamp
- EXPECT_TRUE(video_frame);
- return video_frame;
- }
-
- scoped_refptr<media::VideoFrame> CreateTestRGBAHardwareVideoFrame() {
- return CreateTestHardwareVideoFrame(media::PIXEL_FORMAT_ARGB,
- GL_TEXTURE_2D);
- }
-
- scoped_refptr<media::VideoFrame> CreateTestStreamTextureHardwareVideoFrame(
- bool needs_copy) {
- scoped_refptr<media::VideoFrame> video_frame = CreateTestHardwareVideoFrame(
- media::PIXEL_FORMAT_ARGB, GL_TEXTURE_EXTERNAL_OES);
- video_frame->metadata()->SetBoolean(
- media::VideoFrameMetadata::COPY_REQUIRED, needs_copy);
- return video_frame;
- }
-
- scoped_refptr<media::VideoFrame> CreateTestYuvHardwareVideoFrame(
- media::VideoPixelFormat format,
- size_t num_textures,
- unsigned target) {
- const int kDimension = 10;
- gfx::Size size(kDimension, kDimension);
-
- gpu::MailboxHolder mailbox_holders[media::VideoFrame::kMaxPlanes];
- for (size_t i = 0; i < num_textures; ++i) {
- gpu::Mailbox mailbox;
- mailbox.name[0] = 50 + 1;
- mailbox_holders[i] =
- gpu::MailboxHolder(mailbox, kMailboxSyncToken, target);
- }
- scoped_refptr<media::VideoFrame> video_frame =
- media::VideoFrame::WrapNativeTextures(
- format, mailbox_holders,
- base::Bind(&VideoResourceUpdaterTest::SetReleaseSyncToken,
- base::Unretained(this)),
- size, // coded_size
- gfx::Rect(size), // visible_rect
- size, // natural_size
- base::TimeDelta()); // timestamp
- EXPECT_TRUE(video_frame);
- return video_frame;
- }
-
- static const gpu::SyncToken kMailboxSyncToken;
-
- UploadCounterGLES2Interface* gl_;
- scoped_refptr<viz::TestContextProvider> context_provider_;
- std::unique_ptr<FakeLayerTreeFrameSink> layer_tree_frame_sink_software_;
- std::unique_ptr<LayerTreeResourceProvider> resource_provider3d_;
- std::unique_ptr<LayerTreeResourceProvider> resource_provider_software_;
- gpu::SyncToken release_sync_token_;
- bool use_r16_texture_ = false;
-};
-
-const gpu::SyncToken VideoResourceUpdaterTest::kMailboxSyncToken =
- gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x123),
- 7);
-
-TEST_F(VideoResourceUpdaterTest, SoftwareFrame) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
-}
-
-TEST_F(VideoResourceUpdaterTest, HighBitFrameNoF16) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
-}
-
-class VideoResourceUpdaterTestWithF16 : public VideoResourceUpdaterTest {
- public:
- VideoResourceUpdaterTestWithF16() : VideoResourceUpdaterTest() {
- gl_->set_support_texture_half_float_linear(true);
- }
-};
-
-TEST_F(VideoResourceUpdaterTestWithF16, HighBitFrame) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
- EXPECT_NEAR(resources.multiplier, 2.0, 0.1);
- EXPECT_NEAR(resources.offset, 0.5, 0.1);
-
- // Create the resource again, to test the path where the
- // resources are cached.
- VideoFrameExternalResources resources2 =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources2.type);
- EXPECT_NEAR(resources2.multiplier, 2.0, 0.1);
- EXPECT_NEAR(resources2.offset, 0.5, 0.1);
-}
-
-class VideoResourceUpdaterTestWithR16 : public VideoResourceUpdaterTest {
- public:
- VideoResourceUpdaterTestWithR16() : VideoResourceUpdaterTest() {
- use_r16_texture_ = true;
- gl_->set_support_texture_norm16(true);
- }
-};
-
-TEST_F(VideoResourceUpdaterTestWithR16, HighBitFrame) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
-
- // Max 10-bit values as read by a sampler.
- double max_10bit_value = ((1 << 10) - 1) / 65535.0;
- EXPECT_NEAR(resources.multiplier * max_10bit_value, 1.0, 0.0001);
- EXPECT_NEAR(resources.offset, 0.0, 0.1);
-
- // Create the resource again, to test the path where the
- // resources are cached.
- VideoFrameExternalResources resources2 =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources2.type);
- EXPECT_NEAR(resources2.multiplier * max_10bit_value, 1.0, 0.0001);
- EXPECT_NEAR(resources2.offset, 0.0, 0.1);
-}
-
-TEST_F(VideoResourceUpdaterTest, HighBitFrameSoftwareCompositor) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
-}
-
-TEST_F(VideoResourceUpdaterTest, WonkySoftwareFrame) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- scoped_refptr<media::VideoFrame> video_frame = CreateWonkyTestYUVVideoFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
-}
-
-TEST_F(VideoResourceUpdaterTest, WonkySoftwareFrameSoftwareCompositor) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
- scoped_refptr<media::VideoFrame> video_frame = CreateWonkyTestYUVVideoFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
-}
-
-TEST_F(VideoResourceUpdaterTest, ReuseResource) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
- video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
-
- // Allocate the resources for a YUV video frame.
- gl_->ResetUploadCount();
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
- EXPECT_EQ(3u, resources.resources.size());
- EXPECT_EQ(3u, resources.release_callbacks.size());
- // Expect exactly three texture uploads, one for each plane.
- EXPECT_EQ(3, gl_->UploadCount());
-
- // Simulate the ResourceProvider releasing the resources back to the video
- // updater.
- for (auto& release_callback : resources.release_callbacks)
- std::move(release_callback).Run(gpu::SyncToken(), false);
-
- // Allocate resources for the same frame.
- gl_->ResetUploadCount();
- resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
- EXPECT_EQ(3u, resources.resources.size());
- EXPECT_EQ(3u, resources.release_callbacks.size());
- // The data should be reused so expect no texture uploads.
- EXPECT_EQ(0, gl_->UploadCount());
-}
-
-TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDelete) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
- video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
-
- // Allocate the resources for a YUV video frame.
- gl_->ResetUploadCount();
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
- EXPECT_EQ(3u, resources.resources.size());
- EXPECT_EQ(3u, resources.release_callbacks.size());
- // Expect exactly three texture uploads, one for each plane.
- EXPECT_EQ(3, gl_->UploadCount());
-
- // Allocate resources for the same frame.
- gl_->ResetUploadCount();
- resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
- EXPECT_EQ(3u, resources.resources.size());
- EXPECT_EQ(3u, resources.release_callbacks.size());
- // The data should be reused so expect no texture uploads.
- EXPECT_EQ(0, gl_->UploadCount());
-}
-
-TEST_F(VideoResourceUpdaterTest, SoftwareFrameSoftwareCompositor) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
-}
-
-TEST_F(VideoResourceUpdaterTest, ReuseResourceSoftwareCompositor) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
- video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
-
- // Allocate the resources for a software video frame.
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ(1u, resources.release_callbacks.size());
- // Expect exactly one allocated shared bitmap.
- EXPECT_EQ(1u, layer_tree_frame_sink_software_->shared_bitmaps().size());
- auto shared_bitmaps = layer_tree_frame_sink_software_->shared_bitmaps();
-
- // Simulate the ResourceProvider releasing the resource back to the video
- // updater.
- std::move(resources.release_callbacks[0]).Run(gpu::SyncToken(), false);
-
- // Allocate resources for the same frame.
- resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ(1u, resources.release_callbacks.size());
-
- // Ensure that the same shared bitmap was reused.
- EXPECT_EQ(layer_tree_frame_sink_software_->shared_bitmaps(), shared_bitmaps);
-}
-
-TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDeleteSoftwareCompositor) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
- video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
-
- // Allocate the resources for a software video frame.
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ(1u, resources.release_callbacks.size());
- // Expect exactly one allocated shared bitmap.
- EXPECT_EQ(1u, layer_tree_frame_sink_software_->shared_bitmaps().size());
- auto shared_bitmaps = layer_tree_frame_sink_software_->shared_bitmaps();
-
- // Allocate resources for the same frame.
- resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ(1u, resources.release_callbacks.size());
-
- // Ensure that the same shared bitmap was reused.
- EXPECT_EQ(layer_tree_frame_sink_software_->shared_bitmaps(), shared_bitmaps);
-}
-
-TEST_F(VideoResourceUpdaterTest, ChangeResourceSizeSoftwareCompositor) {
- constexpr gfx::Size kSize1(10, 10);
- constexpr gfx::Size kSize2(20, 20);
-
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
-
- // Allocate the resources for a software video frame.
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(
- CreateTestYUVVideoFrame(kSize1));
- // Expect exactly one allocated shared bitmap.
- EXPECT_EQ(1u, layer_tree_frame_sink_software_->shared_bitmaps().size());
- auto shared_bitmaps = layer_tree_frame_sink_software_->shared_bitmaps();
-
- // Simulate the ResourceProvider releasing the resource back to the video
- // updater.
- std::move(resources.release_callbacks[0]).Run(gpu::SyncToken(), false);
-
- // Allocate resources for the next frame with a different size.
- resources = updater->CreateExternalResourcesFromVideoFrame(
- CreateTestYUVVideoFrame(kSize2));
-
- // The first resource was released, so it can be reused but it's the wrong
- // size. We should expect the first shared bitmap to be deleted and a new
- // shared bitmap to be allocated.
- EXPECT_EQ(1u, layer_tree_frame_sink_software_->shared_bitmaps().size());
- EXPECT_NE(layer_tree_frame_sink_software_->shared_bitmaps(), shared_bitmaps);
-}
-
-TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
-
- scoped_refptr<media::VideoFrame> video_frame =
- CreateTestRGBAHardwareVideoFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ(1u, resources.release_callbacks.size());
-
- video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_I420, 3,
- GL_TEXTURE_RECTANGLE_ARB);
-
- resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
- EXPECT_EQ(3u, resources.resources.size());
- EXPECT_EQ(3u, resources.release_callbacks.size());
- EXPECT_FALSE(resources.resources[0].read_lock_fences_enabled);
- EXPECT_FALSE(resources.resources[1].read_lock_fences_enabled);
- EXPECT_FALSE(resources.resources[2].read_lock_fences_enabled);
-
- video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_I420, 3,
- GL_TEXTURE_RECTANGLE_ARB);
- video_frame->metadata()->SetBoolean(
- media::VideoFrameMetadata::READ_LOCK_FENCES_ENABLED, true);
-
- resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_TRUE(resources.resources[0].read_lock_fences_enabled);
- EXPECT_TRUE(resources.resources[1].read_lock_fences_enabled);
- EXPECT_TRUE(resources.resources[2].read_lock_fences_enabled);
-}
-
-TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_StreamTexture) {
- // Note that |use_stream_video_draw_quad| is true for this test.
- std::unique_ptr<VideoResourceUpdater> updater =
- CreateUpdaterForHardware(true);
- gl_->ResetTextureCreationCount();
- scoped_refptr<media::VideoFrame> video_frame =
- CreateTestStreamTextureHardwareVideoFrame(false);
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::STREAM_TEXTURE, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
- resources.resources[0].mailbox_holder.texture_target);
- EXPECT_EQ(1u, resources.release_callbacks.size());
- EXPECT_EQ(0, gl_->TextureCreationCount());
-
- // A copied stream texture should return an RGBA resource in a new
- // GL_TEXTURE_2D texture.
- gl_->ResetTextureCreationCount();
- video_frame = CreateTestStreamTextureHardwareVideoFrame(true);
- resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ((GLenum)GL_TEXTURE_2D,
- resources.resources[0].mailbox_holder.texture_target);
- EXPECT_EQ(1u, resources.release_callbacks.size());
- EXPECT_EQ(0, gl_->TextureCreationCount());
-}
-
-TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_TextureQuad) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- gl_->ResetTextureCreationCount();
- scoped_refptr<media::VideoFrame> video_frame =
- CreateTestStreamTextureHardwareVideoFrame(false);
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
- resources.resources[0].mailbox_holder.texture_target);
- EXPECT_EQ(1u, resources.release_callbacks.size());
- EXPECT_EQ(0, gl_->TextureCreationCount());
-}
-
-// Passthrough the sync token returned by the compositor if we don't have an
-// existing release sync token.
-TEST_F(VideoResourceUpdaterTest, PassReleaseSyncToken) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
-
- const gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x123),
- 123);
-
- {
- scoped_refptr<media::VideoFrame> video_frame =
- CreateTestRGBAHardwareVideoFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
-
- ASSERT_EQ(resources.release_callbacks.size(), 1u);
- std::move(resources.release_callbacks[0]).Run(sync_token, false);
- }
-
- EXPECT_EQ(release_sync_token_, sync_token);
-}
-
-// Generate new sync token because video frame has an existing sync token.
-TEST_F(VideoResourceUpdaterTest, GenerateReleaseSyncToken) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
-
- const gpu::SyncToken sync_token1(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x123),
- 123);
-
- const gpu::SyncToken sync_token2(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x234),
- 234);
-
- {
- scoped_refptr<media::VideoFrame> video_frame =
- CreateTestRGBAHardwareVideoFrame();
-
- VideoFrameExternalResources resources1 =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- ASSERT_EQ(resources1.release_callbacks.size(), 1u);
- std::move(resources1.release_callbacks[0]).Run(sync_token1, false);
-
- VideoFrameExternalResources resources2 =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- ASSERT_EQ(resources2.release_callbacks.size(), 1u);
- std::move(resources2.release_callbacks[0]).Run(sync_token2, false);
- }
-
- EXPECT_TRUE(release_sync_token_.HasData());
- EXPECT_NE(release_sync_token_, sync_token1);
- EXPECT_NE(release_sync_token_, sync_token2);
-}
-
-// Pass mailbox sync token as is if no GL operations are performed before frame
-// resources are handed off to the compositor.
-TEST_F(VideoResourceUpdaterTest, PassMailboxSyncToken) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
-
- scoped_refptr<media::VideoFrame> video_frame =
- CreateTestRGBAHardwareVideoFrame();
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
-
- ASSERT_EQ(resources.resources.size(), 1u);
- EXPECT_TRUE(resources.resources[0].mailbox_holder.sync_token.HasData());
- EXPECT_EQ(resources.resources[0].mailbox_holder.sync_token,
- kMailboxSyncToken);
-}
-
-// Generate new sync token for compositor when copying the texture.
-TEST_F(VideoResourceUpdaterTest, GenerateSyncTokenOnTextureCopy) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
-
- scoped_refptr<media::VideoFrame> video_frame =
- CreateTestStreamTextureHardwareVideoFrame(true /* needs_copy */);
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
-
- ASSERT_EQ(resources.resources.size(), 1u);
- EXPECT_TRUE(resources.resources[0].mailbox_holder.sync_token.HasData());
- EXPECT_NE(resources.resources[0].mailbox_holder.sync_token,
- kMailboxSyncToken);
-}
-
-// NV12 VideoFrames backed by a single native texture can be sampled out
-// by GL as RGB. To use them as HW overlays we need to know the format
-// of the underlying buffer, that is YUV_420_BIPLANAR.
-TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_SingleNV12) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- gl_->ResetTextureCreationCount();
- scoped_refptr<media::VideoFrame> video_frame = CreateTestHardwareVideoFrame(
- media::PIXEL_FORMAT_NV12, GL_TEXTURE_EXTERNAL_OES);
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGB, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
- resources.resources[0].mailbox_holder.texture_target);
- EXPECT_EQ(gfx::BufferFormat::YUV_420_BIPLANAR,
- resources.resources[0].buffer_format);
-
- video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_NV12, 1,
- GL_TEXTURE_RECTANGLE_ARB);
- resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::RGB, resources.type);
- EXPECT_EQ(1u, resources.resources.size());
- EXPECT_EQ((GLenum)GL_TEXTURE_RECTANGLE_ARB,
- resources.resources[0].mailbox_holder.texture_target);
- EXPECT_EQ(gfx::BufferFormat::YUV_420_BIPLANAR,
- resources.resources[0].buffer_format);
-
- EXPECT_EQ(0, gl_->TextureCreationCount());
-}
-
-TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_DualNV12) {
- std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
- gl_->ResetTextureCreationCount();
- scoped_refptr<media::VideoFrame> video_frame =
- CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_NV12, 2,
- GL_TEXTURE_EXTERNAL_OES);
-
- VideoFrameExternalResources resources =
- updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
- EXPECT_EQ(2u, resources.resources.size());
- EXPECT_EQ(2u, resources.release_callbacks.size());
- EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
- resources.resources[0].mailbox_holder.texture_target);
- // |updater| doesn't set |buffer_format| in this case.
- EXPECT_EQ(gfx::BufferFormat::RGBA_8888, resources.resources[0].buffer_format);
-
- video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_NV12, 2,
- GL_TEXTURE_RECTANGLE_ARB);
- resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
- EXPECT_EQ(2u, resources.resources.size());
- EXPECT_EQ((GLenum)GL_TEXTURE_RECTANGLE_ARB,
- resources.resources[0].mailbox_holder.texture_target);
- EXPECT_EQ(gfx::BufferFormat::RGBA_8888, resources.resources[0].buffer_format);
- // When TestWebGraphicsContext3D is used, createAndConsumeTextureCHROMIUM will
- // call createTexture. But this is incorrect, so when this is converted to
- // TestGLES2Interface, GenTextures will not being called.
- EXPECT_EQ(0, gl_->TextureCreationCount());
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/scheduler/compositor_timing_history.cc b/chromium/cc/scheduler/compositor_timing_history.cc
index dd4d8f8a958..d4ed618a8db 100644
--- a/chromium/cc/scheduler/compositor_timing_history.cc
+++ b/chromium/cc/scheduler/compositor_timing_history.cc
@@ -45,7 +45,6 @@ class CompositorTimingHistory::UMAReporter {
virtual void AddActivateDuration(base::TimeDelta duration) = 0;
virtual void AddDrawDuration(base::TimeDelta duration) = 0;
virtual void AddSubmitToAckLatency(base::TimeDelta duration) = 0;
- virtual void AddSubmitAckWasFast(bool was_fast) = 0;
// crbug.com/758439: the following 3 functions are used to report timing in
// certain conditions targeting blink / compositor animations.
@@ -268,10 +267,6 @@ class RendererUMAReporter : public CompositorTimingHistory::UMAReporter {
duration);
}
- void AddSubmitAckWasFast(bool was_fast) override {
- UMA_HISTOGRAM_BOOLEAN("Scheduling.Renderer.SwapAckWasFast", was_fast);
- }
-
void AddMainAndImplFrameTimeDelta(base::TimeDelta delta) override {
UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
"Scheduling.Renderer.MainAndImplFrameTimeDelta", delta);
@@ -282,39 +277,26 @@ class BrowserUMAReporter : public CompositorTimingHistory::UMAReporter {
public:
~BrowserUMAReporter() override = default;
- void AddBeginMainFrameIntervalCritical(base::TimeDelta interval) override {
- UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
- "Scheduling.Browser.BeginMainFrameIntervalCritical", interval);
- }
+ // BeginMainFrameIntervalCritical is not meaningful to measure on browser
+ // side because browser rendering fps is not at 60.
+ void AddBeginMainFrameIntervalCritical(base::TimeDelta interval) override {}
void AddBeginMainFrameIntervalNotCritical(base::TimeDelta interval) override {
- UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
- "Scheduling.Browser.BeginMainFrameIntervalNotCritical", interval);
}
- void AddCommitInterval(base::TimeDelta interval) override {
- UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
- "Scheduling.Browser.CommitInterval", interval);
- }
+ // CommitInterval is not meaningful to measure on browser side because
+ // browser rendering fps is not at 60.
+ void AddCommitInterval(base::TimeDelta interval) override {}
- void AddDrawInterval(base::TimeDelta interval) override {
- UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED("Scheduling.Browser.DrawInterval",
- interval);
- }
+ // DrawInterval is not meaningful to measure on browser side because
+ // browser rendering fps is not at 60.
+ void AddDrawInterval(base::TimeDelta interval) override {}
void AddDrawIntervalWithCompositedAnimations(
- base::TimeDelta interval) override {
- // Still report, but the data is not meaningful.
- UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
- "Scheduling.Browser.DrawIntervalWithCompositedAnimations", interval);
- }
+ base::TimeDelta interval) override {}
void AddDrawIntervalWithMainThreadAnimations(
- base::TimeDelta interval) override {
- // Still report, but the data is not meaningful.
- UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
- "Scheduling.Browser.DrawIntervalWithMainThreadAnimations", interval);
- }
+ base::TimeDelta interval) override {}
void AddBeginImplFrameLatency(base::TimeDelta delta) override {
UMA_HISTOGRAM_CUSTOM_TIMES_DURATION(
@@ -328,10 +310,7 @@ class BrowserUMAReporter : public CompositorTimingHistory::UMAReporter {
}
void AddBeginMainFrameQueueDurationNotCriticalDuration(
- base::TimeDelta duration) override {
- UMA_HISTOGRAM_CUSTOM_TIMES_DURATION(
- "Scheduling.Browser.BeginMainFrameQueueDurationNotCritical", duration);
- }
+ base::TimeDelta duration) override {}
void AddBeginMainFrameStartToCommitDuration(
base::TimeDelta duration) override {
@@ -357,15 +336,9 @@ class BrowserUMAReporter : public CompositorTimingHistory::UMAReporter {
void AddReadyToActivateToWillActivateDuration(
base::TimeDelta duration,
bool pending_tree_is_impl_side) override {
- if (pending_tree_is_impl_side) {
- UMA_HISTOGRAM_CUSTOM_TIMES_DURATION_SUFFIX(
- "Scheduling.Browser.ReadyToActivateToActivationDuration", ".Impl",
- duration);
- } else {
- UMA_HISTOGRAM_CUSTOM_TIMES_DURATION_SUFFIX(
- "Scheduling.Browser.ReadyToActivateToActivationDuration", ".Main",
- duration);
- }
+ UMA_HISTOGRAM_CUSTOM_TIMES_DURATION_SUFFIX(
+ "Scheduling.Browser.ReadyToActivateToActivationDuration", ".Main",
+ duration);
}
void AddPrepareTilesDuration(base::TimeDelta duration) override {
@@ -388,10 +361,6 @@ class BrowserUMAReporter : public CompositorTimingHistory::UMAReporter {
duration);
}
- void AddSubmitAckWasFast(bool was_fast) override {
- UMA_HISTOGRAM_BOOLEAN("Scheduling.Browser.SwapAckWasFast", was_fast);
- }
-
void AddMainAndImplFrameTimeDelta(base::TimeDelta delta) override {
UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
"Scheduling.Browser.MainAndImplFrameTimeDelta", delta);
@@ -429,7 +398,6 @@ class NullUMAReporter : public CompositorTimingHistory::UMAReporter {
void AddActivateDuration(base::TimeDelta duration) override {}
void AddDrawDuration(base::TimeDelta duration) override {}
void AddSubmitToAckLatency(base::TimeDelta duration) override {}
- void AddSubmitAckWasFast(bool was_fast) override {}
void AddMainAndImplFrameTimeDelta(base::TimeDelta delta) override {}
};
@@ -614,7 +582,6 @@ void CompositorTimingHistory::WillBeginImplFrame(
if (submit_ack_watchdog_enabled_) {
base::TimeDelta submit_not_acked_time_ = now - submit_start_time_;
if (submit_not_acked_time_ >= kSubmitAckWatchdogTimeout) {
- uma_reporter_->AddSubmitAckWasFast(false);
// Only record this UMA once per submitted CompositorFrame.
submit_ack_watchdog_enabled_ = false;
}
@@ -953,11 +920,8 @@ 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_) {
- bool was_fast = submit_to_ack_duration < kSubmitAckWatchdogTimeout;
- uma_reporter_->AddSubmitAckWasFast(was_fast);
+ if (submit_ack_watchdog_enabled_)
submit_ack_watchdog_enabled_ = false;
- }
submit_start_time_ = base::TimeTicks();
}
@@ -965,9 +929,8 @@ void CompositorTimingHistory::SetTreePriority(TreePriority priority) {
tree_priority_ = priority;
}
-void CompositorTimingHistory::ClearHistoryOnNavigation() {
- TRACE_EVENT0("cc,benchmark",
- "CompositorTimingHistory::ClearHistoryOnNavigation");
+void CompositorTimingHistory::ClearHistory() {
+ TRACE_EVENT0("cc,benchmark", "CompositorTimingHistory::ClearHistory");
begin_main_frame_queue_duration_history_.Clear();
begin_main_frame_queue_duration_critical_history_.Clear();
diff --git a/chromium/cc/scheduler/compositor_timing_history.h b/chromium/cc/scheduler/compositor_timing_history.h
index 84aa1545eba..842583f1106 100644
--- a/chromium/cc/scheduler/compositor_timing_history.h
+++ b/chromium/cc/scheduler/compositor_timing_history.h
@@ -93,7 +93,7 @@ class CC_EXPORT CompositorTimingHistory {
return begin_main_frame_sent_time_;
}
- void ClearHistoryOnNavigation();
+ void ClearHistory();
size_t begin_main_frame_start_to_ready_to_commit_sample_count() const {
return begin_main_frame_start_to_ready_to_commit_duration_history_
.sample_count();
@@ -126,7 +126,7 @@ class CC_EXPORT CompositorTimingHistory {
base::TimeTicks draw_end_time_prev_;
// If you add any history here, please remember to reset it in
- // ClearHistoryOnNavigation.
+ // ClearHistory.
RollingTimeDeltaHistory begin_main_frame_queue_duration_history_;
RollingTimeDeltaHistory begin_main_frame_queue_duration_critical_history_;
RollingTimeDeltaHistory begin_main_frame_queue_duration_not_critical_history_;
diff --git a/chromium/cc/scheduler/compositor_timing_history_unittest.cc b/chromium/cc/scheduler/compositor_timing_history_unittest.cc
index 564bc81c8bd..a5e8387d8b2 100644
--- a/chromium/cc/scheduler/compositor_timing_history_unittest.cc
+++ b/chromium/cc/scheduler/compositor_timing_history_unittest.cc
@@ -5,7 +5,7 @@
#include "cc/scheduler/compositor_timing_history.h"
#include "base/macros.h"
-#include "base/test/histogram_tester.h"
+#include "base/test/metrics/histogram_tester.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/cc/scheduler/draw_result.h b/chromium/cc/scheduler/draw_result.h
index 83fe4413f02..37ffb04c34a 100644
--- a/chromium/cc/scheduler/draw_result.h
+++ b/chromium/cc/scheduler/draw_result.h
@@ -7,6 +7,8 @@
namespace cc {
+// Note that these values are reported in UMA. So entries should never be
+// renumbered, and numeric values should never be reused.
enum DrawResult {
INVALID_RESULT,
DRAW_SUCCESS,
@@ -14,6 +16,8 @@ enum DrawResult {
DRAW_ABORTED_MISSING_HIGH_RES_CONTENT,
DRAW_ABORTED_CANT_DRAW,
DRAW_ABORTED_DRAINING_PIPELINE,
+ // Magic constant used by the histogram macros.
+ kMaxValue = DRAW_ABORTED_DRAINING_PIPELINE,
};
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index 87db539737f..184fae211c5 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -318,13 +318,15 @@ void Scheduler::SetVideoNeedsBeginFrames(bool video_needs_begin_frames) {
ProcessScheduledActions();
}
-void Scheduler::OnDrawForLayerTreeFrameSink(bool resourceless_software_draw) {
+void Scheduler::OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,
+ bool skip_draw) {
DCHECK(settings_.using_synchronous_renderer_compositor);
DCHECK_EQ(state_machine_.begin_impl_frame_state(),
SchedulerStateMachine::BeginImplFrameState::IDLE);
DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
state_machine_.SetResourcelessSoftwareDraw(resourceless_software_draw);
+ state_machine_.SetSkipDraw(skip_draw);
state_machine_.OnBeginImplFrameDeadline();
ProcessScheduledActions();
@@ -520,8 +522,7 @@ void Scheduler::SendBeginFrameAck(const viz::BeginFrameArgs& args,
if (!did_submit) {
DCHECK(!inside_scheduled_action_);
base::AutoReset<bool> mark_inside(&inside_scheduled_action_, true);
- client_->DidNotProduceFrame(
- viz::BeginFrameAck(args.source_id, args.sequence_number, did_submit));
+ client_->DidNotProduceFrame(viz::BeginFrameAck(args, did_submit));
}
if (begin_frame_source_)
@@ -774,7 +775,8 @@ void Scheduler::ProcessScheduledActions() {
break;
case SchedulerStateMachine::Action::INVALIDATE_LAYER_TREE_FRAME_SINK: {
state_machine_.WillInvalidateLayerTreeFrameSink();
- client_->ScheduledActionInvalidateLayerTreeFrameSink();
+ client_->ScheduledActionInvalidateLayerTreeFrameSink(
+ state_machine_.RedrawPending());
break;
}
}
@@ -961,14 +963,13 @@ bool Scheduler::IsBeginMainFrameSentOrStarted() const {
}
viz::BeginFrameAck Scheduler::CurrentBeginFrameAckForActiveTree() const {
- return viz::BeginFrameAck(begin_main_frame_args_.source_id,
- begin_main_frame_args_.sequence_number, true);
+ return viz::BeginFrameAck(begin_main_frame_args_, true);
}
-void Scheduler::ClearHistoryOnNavigation() {
+void Scheduler::ClearHistory() {
// Ensure we reset decisions based on history from the previous navigation.
state_machine_.SetSkipNextBeginMainFrameToReduceLatency(false);
- compositor_timing_history_->ClearHistoryOnNavigation();
+ compositor_timing_history_->ClearHistory();
ProcessScheduledActions();
}
diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h
index 79ec95b21d4..a9926c86687 100644
--- a/chromium/cc/scheduler/scheduler.h
+++ b/chromium/cc/scheduler/scheduler.h
@@ -44,7 +44,8 @@ class SchedulerClient {
virtual void ScheduledActionActivateSyncTree() = 0;
virtual void ScheduledActionBeginLayerTreeFrameSinkCreation() = 0;
virtual void ScheduledActionPrepareTiles() = 0;
- virtual void ScheduledActionInvalidateLayerTreeFrameSink() = 0;
+ virtual void ScheduledActionInvalidateLayerTreeFrameSink(
+ bool needs_redraw) = 0;
virtual void ScheduledActionPerformImplSideInvalidation() = 0;
virtual void DidFinishImplFrame() = 0;
virtual void DidNotProduceFrame(const viz::BeginFrameAck& ack) = 0;
@@ -79,7 +80,8 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
void OnBeginFrameSourcePausedChanged(bool paused) override;
bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) override;
- void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw);
+ void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,
+ bool skip_draw);
const SchedulerSettings& settings() const { return settings_; }
@@ -172,7 +174,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
viz::BeginFrameAck CurrentBeginFrameAckForActiveTree() const;
- void ClearHistoryOnNavigation();
+ void ClearHistory();
protected:
// Virtual for testing.
diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc
index 8f5409fc010..a81baa256ea 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine.cc
@@ -323,6 +323,10 @@ bool SchedulerStateMachine::ShouldDraw() const {
if (did_draw_)
return false;
+ // Don't draw if an early check determined the frame does not have damage.
+ if (skip_draw_)
+ return false;
+
// Don't draw if we are waiting on the first commit after a surface.
if (layer_tree_frame_sink_state_ != LayerTreeFrameSinkState::ACTIVE)
return false;
@@ -1201,6 +1205,10 @@ void SchedulerStateMachine::SetCanDraw(bool can_draw) {
can_draw_ = can_draw;
}
+void SchedulerStateMachine::SetSkipDraw(bool skip_draw) {
+ skip_draw_ = skip_draw;
+}
+
void SchedulerStateMachine::SetNeedsRedraw() {
needs_redraw_ = true;
}
diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h
index 9fec8c62146..cd996142e4f 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.h
+++ b/chromium/cc/scheduler/scheduler_state_machine.h
@@ -246,7 +246,8 @@ class CC_EXPORT SchedulerStateMachine {
// Indicates production should be skipped to recover latency.
void SetSkipNextBeginMainFrameToReduceLatency(bool skip);
- // Resourceless software draws are allowed even when invisible.
+ // For Android WebView, resourceless software draws are allowed even when
+ // invisible.
void SetResourcelessSoftwareDraw(bool resourceless_draw);
// Indicates whether drawing would, at this time, make sense.
@@ -254,6 +255,10 @@ class CC_EXPORT SchedulerStateMachine {
// when such behavior would be undesirable.
void SetCanDraw(bool can);
+ // For Android WebView, indicates that the draw should be skipped because the
+ // frame sink is not ready to receive frames.
+ void SetSkipDraw(bool skip);
+
// Indicates that scheduled BeginMainFrame is started.
void NotifyBeginMainFrameStarted();
@@ -386,6 +391,7 @@ class CC_EXPORT SchedulerStateMachine {
bool begin_frame_source_paused_ = false;
bool resourceless_draw_ = false;
bool can_draw_ = false;
+ bool skip_draw_ = false;
bool has_pending_tree_ = false;
bool pending_tree_is_ready_for_activation_ = false;
bool active_tree_needs_first_draw_ = false;
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc
index d1fcefb1c79..4d9c77ad14d 100644
--- a/chromium/cc/scheduler/scheduler_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_unittest.cc
@@ -14,6 +14,7 @@
#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
#include "base/run_loop.h"
+#include "base/test/test_mock_time_task_runner.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "cc/test/scheduler_test_common.h"
@@ -21,7 +22,6 @@
#include "components/viz/test/begin_frame_args_test.h"
#include "components/viz/test/fake_delay_based_time_source.h"
#include "components/viz/test/fake_external_begin_frame_source.h"
-#include "components/viz/test/ordered_simple_task_runner.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -52,6 +52,7 @@ class FakeSchedulerClient : public SchedulerClient,
states_.clear();
will_begin_impl_frame_causes_redraw_ = false;
will_begin_impl_frame_requests_one_begin_impl_frame_ = false;
+ invalidate_needs_redraw_ = true;
draw_will_happen_ = true;
swap_will_happen_if_draw_happens_ = true;
num_draws_ = 0;
@@ -63,6 +64,7 @@ class FakeSchedulerClient : public SchedulerClient,
bool needs_begin_frames() { return scheduler_->begin_frames_expected(); }
int num_draws() const { return num_draws_; }
+ bool invalidate_needs_redraw() const { return invalidate_needs_redraw_; }
const std::vector<std::string> Actions() const {
return std::vector<std::string>(actions_.begin(), actions_.end());
}
@@ -86,6 +88,9 @@ class FakeSchedulerClient : public SchedulerClient,
void SetWillBeginImplFrameCausesRedraw(bool causes_redraw) {
will_begin_impl_frame_causes_redraw_ = causes_redraw;
}
+ void SetInvalidateNeedsRedraw(bool needs_redraw) {
+ invalidate_needs_redraw_ = needs_redraw;
+ }
void SetDrawWillHappen(bool draw_will_happen) {
draw_will_happen_ = draw_will_happen;
}
@@ -187,9 +192,10 @@ class FakeSchedulerClient : public SchedulerClient,
scheduler_->WillPrepareTiles();
scheduler_->DidPrepareTiles();
}
- void ScheduledActionInvalidateLayerTreeFrameSink() override {
+ void ScheduledActionInvalidateLayerTreeFrameSink(bool needs_redraw) override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
+ invalidate_needs_redraw_ = needs_redraw;
actions_.push_back("ScheduledActionInvalidateLayerTreeFrameSink");
states_.push_back(scheduler_->AsValue());
}
@@ -256,6 +262,7 @@ class FakeSchedulerClient : public SchedulerClient,
bool inside_begin_impl_frame_ = false;
bool will_begin_impl_frame_causes_redraw_;
bool will_begin_impl_frame_requests_one_begin_impl_frame_;
+ bool invalidate_needs_redraw_ = true;
bool draw_will_happen_;
bool swap_will_happen_if_draw_happens_;
bool automatic_ack_ = true;
@@ -276,20 +283,71 @@ enum BeginFrameSourceType {
THROTTLED_BFS,
};
+class SchedulerTestTaskRunner : public base::TestMockTimeTaskRunner {
+ public:
+ SchedulerTestTaskRunner()
+ : base::TestMockTimeTaskRunner(
+ base::TestMockTimeTaskRunner::Type::kStandalone) {
+ AdvanceMockTickClock(base::TimeDelta::FromMicroseconds(110000));
+ }
+
+ void RunUntilTime(base::TimeTicks end_time) {
+ FastForwardBy(end_time - NowTicks());
+ }
+
+ // Runs all tasks posted before this call.
+ void RunPendingTasks() {
+ base::circular_deque<base::TestPendingTask> tasks = TakePendingTasks();
+ while (!tasks.empty()) {
+ base::TestPendingTask task = std::move(tasks.front());
+ tasks.pop_front();
+ // Set clock to the beginning of task and run it.
+ AdvanceMockTickClock(task.GetTimeToRun() - NowTicks());
+ std::move(task.task).Run();
+ }
+ }
+
+ // Runs tasks while condition is met.
+ // Condition is being checked when task exists and before it gets selected.
+ void RunTasksWhile(base::RepeatingCallback<bool()> condition) {
+ run_condition_ = condition;
+ FastForwardUntilNoTasksRemain();
+ run_condition_ = base::nullopt;
+ // We've moved all the pending tasks away to break the execution loop,
+ // now we should restore them.
+ while (!tasks_to_requeue_.empty()) {
+ base::TestPendingTask task = std::move(tasks_to_requeue_.front());
+ tasks_to_requeue_.pop_front();
+ PostDelayedTask(task.location, std::move(task.task),
+ task.GetTimeToRun() - NowTicks());
+ }
+ }
+
+ protected:
+ void OnBeforeSelectingTask() override {
+ // Avoid potential infinite loops.
+ ASSERT_LT(++task_count_, 100u);
+
+ if (run_condition_ && HasPendingTask() && !run_condition_->Run()) {
+ // Execution will not continue because we move all the pending tasks away.
+ tasks_to_requeue_ = TakePendingTasks();
+ }
+ }
+
+ private:
+ ~SchedulerTestTaskRunner() override = default; // Ref-counted.
+
+ size_t task_count_ = 0u;
+ base::Optional<base::RepeatingCallback<bool()>> run_condition_;
+ base::circular_deque<base::TestPendingTask> tasks_to_requeue_;
+};
+
class SchedulerTest : public testing::Test {
public:
SchedulerTest()
- : now_src_(new base::SimpleTestTickClock()),
- task_runner_(new OrderedSimpleTaskRunner(now_src_.get(), true)),
+ : task_runner_(base::MakeRefCounted<SchedulerTestTaskRunner>()),
fake_external_begin_frame_source_(nullptr),
- fake_compositor_timing_history_(nullptr) {
- now_src_->Advance(base::TimeDelta::FromMicroseconds(10000));
- // A bunch of tests require NowTicks()
- // to be > viz::BeginFrameArgs::DefaultInterval()
- now_src_->Advance(base::TimeDelta::FromMilliseconds(100));
- // Fail if we need to run 100 tasks in a row.
- task_runner_->SetRunTaskLimit(100);
- }
+ fake_compositor_timing_history_(nullptr) {}
~SchedulerTest() override = default;
@@ -297,14 +355,14 @@ class SchedulerTest : public testing::Test {
TestScheduler* CreateScheduler(BeginFrameSourceType bfs_type) {
viz::BeginFrameSource* frame_source = nullptr;
unthrottled_frame_source_.reset(new viz::BackToBackBeginFrameSource(
- std::make_unique<viz::FakeDelayBasedTimeSource>(now_src_.get(),
- task_runner_.get())));
+ std::make_unique<viz::FakeDelayBasedTimeSource>(
+ task_runner_->GetMockTickClock(), task_runner_.get())));
fake_external_begin_frame_source_.reset(
new viz::FakeExternalBeginFrameSource(1.0, false));
fake_external_begin_frame_source_->SetClient(client_.get());
synthetic_frame_source_ = std::make_unique<viz::DelayBasedBeginFrameSource>(
- std::make_unique<viz::FakeDelayBasedTimeSource>(now_src_.get(),
- task_runner_.get()),
+ std::make_unique<viz::FakeDelayBasedTimeSource>(
+ task_runner_->GetMockTickClock(), task_runner_.get()),
viz::BeginFrameSource::kNotRestartableId);
switch (bfs_type) {
case EXTERNAL_BFS:
@@ -325,7 +383,7 @@ class SchedulerTest : public testing::Test {
fake_compositor_timing_history_ = fake_compositor_timing_history.get();
scheduler_.reset(new TestScheduler(
- now_src_.get(), client_.get(), scheduler_settings_, 0,
+ task_runner_->GetMockTickClock(), client_.get(), scheduler_settings_, 0,
task_runner_.get(), std::move(fake_compositor_timing_history)));
client_->set_scheduler(scheduler_.get());
scheduler_->SetBeginFrameSource(frame_source);
@@ -352,9 +410,6 @@ class SchedulerTest : public testing::Test {
CreateScheduler(bfs_type);
}
- OrderedSimpleTaskRunner& task_runner() { return *task_runner_; }
- base::SimpleTestTickClock* now_src() { return now_src_.get(); }
-
// As this function contains EXPECT macros, to allow debugging it should be
// called inside EXPECT_SCOPED like so;
// EXPECT_SCOPED(
@@ -387,8 +442,8 @@ class SchedulerTest : public testing::Test {
SCOPED_TRACE("Do first frame to commit after initialize.");
AdvanceFrame();
- now_src_->Advance(base::TimeDelta::FromMilliseconds(1));
- scheduler_->NotifyBeginMainFrameStarted(now_src_->NowTicks());
+ task_runner_->AdvanceMockTickClock(base::TimeDelta::FromMilliseconds(1));
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
scheduler_->NotifyReadyToDraw();
@@ -398,7 +453,9 @@ class SchedulerTest : public testing::Test {
if (scheduler_settings_.using_synchronous_renderer_compositor) {
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ bool skip_draw = false;
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
} else {
// Run the posted deadline task.
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
@@ -465,10 +522,10 @@ class SchedulerTest : public testing::Test {
fake_external_begin_frame_source_.get());
// Creep the time forward so that any viz::BeginFrameArgs is not equal to
// the last one otherwise we violate the viz::BeginFrameSource contract.
- now_src_->Advance(viz::BeginFrameArgs::DefaultInterval());
+ task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
viz::BeginFrameArgs args =
fake_external_begin_frame_source_->CreateBeginFrameArgs(
- BEGINFRAME_FROM_HERE, now_src());
+ BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
args.animate_only = animate_only;
fake_external_begin_frame_source_->TestOnBeginFrame(args);
return args;
@@ -503,8 +560,7 @@ class SchedulerTest : public testing::Test {
ScrollHandlerState scroll_handler_state,
base::TimeDelta durations);
- std::unique_ptr<base::SimpleTestTickClock> now_src_;
- scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
+ scoped_refptr<SchedulerTestTaskRunner> task_runner_;
std::unique_ptr<viz::FakeExternalBeginFrameSource>
fake_external_begin_frame_source_;
std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_frame_source_;
@@ -585,14 +641,14 @@ TEST_F(SchedulerTest, RequestCommit) {
client_->Reset();
// If we don't swap on the deadline, we wait for the next BeginFrame.
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_NO_ACTION();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
// NotifyReadyToCommit should trigger the commit.
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
EXPECT_TRUE(scheduler_->begin_frames_expected());
@@ -612,7 +668,7 @@ TEST_F(SchedulerTest, RequestCommit) {
client_->Reset();
// BeginImplFrame deadline should draw.
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
@@ -625,7 +681,7 @@ TEST_F(SchedulerTest, RequestCommit) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("RemoveObserver(this)");
client_->Reset();
}
@@ -639,7 +695,7 @@ TEST_F(SchedulerTest, RequestCommitAfterSetDeferCommit) {
EXPECT_NO_ACTION();
client_->Reset();
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
// There are no pending tasks or actions.
EXPECT_NO_ACTION();
EXPECT_FALSE(scheduler_->begin_frames_expected());
@@ -675,7 +731,7 @@ TEST_F(SchedulerTest, DeferCommitWithRedraw) {
EXPECT_ACTIONS("WillBeginImplFrame");
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
@@ -707,7 +763,7 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
client_->Reset();
// Finish the first commit.
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
@@ -719,7 +775,7 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
@@ -736,7 +792,7 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
// Finishing the commit before the deadline should post a new deadline task
// to trigger the deadline early.
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
@@ -745,7 +801,7 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
@@ -754,7 +810,7 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
// On the next BeginImplFrame, verify we go back to a quiescent state and
// no longer request BeginImplFrames.
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_FALSE(scheduler_->begin_frames_expected());
client_->Reset();
}
@@ -799,7 +855,7 @@ TEST_F(SchedulerTest, RequestRedrawInsideDraw) {
EXPECT_EQ(0, client->num_draws());
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
@@ -807,7 +863,7 @@ TEST_F(SchedulerTest, RequestRedrawInsideDraw) {
client->SetRequestRedrawsInsideDraw(false);
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client_->num_draws());
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
@@ -815,7 +871,7 @@ TEST_F(SchedulerTest, RequestRedrawInsideDraw) {
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client->num_draws());
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(client->needs_begin_frames());
@@ -837,7 +893,7 @@ TEST_F(SchedulerTest, RequestRedrawInsideFailedDraw) {
// Fail the draw.
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client->num_draws());
// We have a commit pending and the draw failed, and we didn't lose the redraw
@@ -850,7 +906,7 @@ TEST_F(SchedulerTest, RequestRedrawInsideFailedDraw) {
// Fail the draw again.
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(scheduler_->RedrawPending());
@@ -859,7 +915,7 @@ TEST_F(SchedulerTest, RequestRedrawInsideFailedDraw) {
// Draw successfully.
client->SetDrawWillHappen(true);
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(3, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_FALSE(scheduler_->RedrawPending());
@@ -910,16 +966,16 @@ TEST_F(SchedulerTest, RequestCommitInsideDraw) {
client->SetNeedsBeginMainFrameOnNextDraw();
EXPECT_SCOPED(AdvanceFrame());
client->SetNeedsBeginMainFrameOnNextDraw();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(client->needs_begin_frames());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client->num_draws());
EXPECT_FALSE(scheduler_->RedrawPending());
@@ -929,7 +985,7 @@ TEST_F(SchedulerTest, RequestCommitInsideDraw) {
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client->num_draws());
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(scheduler_->CommitPending());
@@ -951,7 +1007,7 @@ TEST_F(SchedulerTest, RequestCommitInsideFailedDraw) {
// Fail the draw.
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client->num_draws());
// We have a commit pending and the draw failed, and we didn't lose the commit
@@ -963,7 +1019,7 @@ TEST_F(SchedulerTest, RequestCommitInsideFailedDraw) {
// Fail the draw again.
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(scheduler_->RedrawPending());
@@ -972,7 +1028,7 @@ TEST_F(SchedulerTest, RequestCommitInsideFailedDraw) {
// Draw successfully.
client->SetDrawWillHappen(true);
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(3, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_FALSE(scheduler_->RedrawPending());
@@ -992,7 +1048,7 @@ TEST_F(SchedulerTest, NoSwapWhenDrawFails) {
// Draw successfully, this starts a new frame.
client->SetNeedsBeginMainFrameOnNextDraw();
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client->num_draws());
scheduler_->SetNeedsRedraw();
@@ -1003,7 +1059,7 @@ TEST_F(SchedulerTest, NoSwapWhenDrawFails) {
client->SetDrawWillHappen(false);
client->SetNeedsBeginMainFrameOnNextDraw();
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client->num_draws());
}
@@ -1042,7 +1098,7 @@ TEST_F(SchedulerTest, PrepareTiles) {
// On the deadline, the actions should have occured in the right order.
client->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(client->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
@@ -1071,7 +1127,7 @@ TEST_F(SchedulerTest, PrepareTiles) {
// then the PrepareTiles action will be triggered after the Draw.
// Afterwards, neither a draw nor PrepareTiles are pending.
client->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(client->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
@@ -1087,7 +1143,7 @@ TEST_F(SchedulerTest, PrepareTiles) {
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_EQ(0, client->num_draws());
@@ -1107,7 +1163,7 @@ TEST_F(SchedulerTest, PrepareTiles) {
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(0, client->num_draws());
EXPECT_FALSE(client->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
@@ -1134,7 +1190,7 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
EXPECT_FALSE(scheduler_->PrepareTilesPending());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
@@ -1151,7 +1207,7 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
@@ -1175,7 +1231,7 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
EXPECT_TRUE(scheduler_->PrepareTilesPending());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
@@ -1199,7 +1255,7 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
EXPECT_TRUE(scheduler_->PrepareTilesPending());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
@@ -1215,7 +1271,7 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
@@ -1241,7 +1297,7 @@ TEST_F(SchedulerTest, DidPrepareTilesPreventsPrepareTilesForOneFrame) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionPrepareTiles");
@@ -1262,7 +1318,7 @@ TEST_F(SchedulerTest, DidPrepareTilesPreventsPrepareTilesForOneFrame) {
// No scheduled prepare tiles because we've already counted a prepare tiles in
// between frames.
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
@@ -1274,7 +1330,7 @@ TEST_F(SchedulerTest, DidPrepareTilesPreventsPrepareTilesForOneFrame) {
// Resume scheduled prepare tiles.
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionPrepareTiles");
@@ -1306,7 +1362,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) {
// Begin new frame.
EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
@@ -1319,14 +1375,14 @@ TEST_F(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) {
// Scheduler won't post deadline in the mode.
client_->Reset();
- task_runner().RunPendingTasks(); // Try to run posted deadline.
+ task_runner_->RunPendingTasks(); // Try to run posted deadline.
// There is no posted deadline.
EXPECT_NO_ACTION();
// Scheduler received ready to draw signal, and posted deadline.
scheduler_->NotifyReadyToDraw();
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
}
@@ -1344,7 +1400,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostLayerTreeFrameSink) {
// Begin new frame.
EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
@@ -1357,7 +1413,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostLayerTreeFrameSink) {
// Scheduler won't post deadline in the mode.
client_->Reset();
- task_runner().RunPendingTasks(); // Try to run posted deadline.
+ task_runner_->RunPendingTasks(); // Try to run posted deadline.
// There is no posted deadline.
EXPECT_NO_ACTION();
@@ -1366,7 +1422,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostLayerTreeFrameSink) {
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
}
@@ -1377,9 +1433,9 @@ void SchedulerTest::AdvanceAndMissOneFrame() {
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
@@ -1397,7 +1453,7 @@ void SchedulerTest::CheckMainFrameSkippedAfterLateCommit(
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_EQ(expect_send_begin_main_frame,
scheduler_->MainThreadMissedLastDeadline());
EXPECT_TRUE(client_->HasAction("WillBeginImplFrame"));
@@ -1417,16 +1473,17 @@ TEST_F(SchedulerTest, MainFrameNotSkippedAfterLateBeginFrame) {
scheduler_->SetNeedsBeginMainFrame();
// Advance frame and create a begin frame.
- now_src_->Advance(viz::BeginFrameArgs::DefaultInterval());
+ task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
viz::BeginFrameArgs args =
fake_external_begin_frame_source_->CreateBeginFrameArgs(
- BEGINFRAME_FROM_HERE, now_src());
+ BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
// Deliver this begin frame super late.
- now_src_->Advance(viz::BeginFrameArgs::DefaultInterval() * 100);
+ task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval() *
+ 100);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_EQ(true, scheduler_->MainThreadMissedLastDeadline());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionDrawIfPossible");
@@ -1544,9 +1601,9 @@ TEST_F(SchedulerTest, MainFrameNotSkippedAfterLateBeginMainFrameAbort) {
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame");
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
// After aborting the frame, make sure we don't skip the
@@ -1560,7 +1617,7 @@ TEST_F(SchedulerTest, MainFrameNotSkippedAfterLateBeginMainFrameAbort) {
EXPECT_TRUE(client_->HasAction("WillBeginImplFrame"));
EXPECT_TRUE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
}
@@ -1579,9 +1636,9 @@ TEST_F(SchedulerTest, MainFrameNotSkippedAfterCanDrawChanges) {
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame");
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
// Make us abort the upcoming draw.
@@ -1607,7 +1664,7 @@ TEST_F(SchedulerTest, MainFrameNotSkippedAfterCanDrawChanges) {
EXPECT_TRUE(client_->HasAction("WillBeginImplFrame"));
EXPECT_TRUE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
}
@@ -1624,9 +1681,9 @@ TEST_F(SchedulerTest, MainFrameNotSkippedWhenNoTimingHistory) {
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame");
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
// Commit after the deadline.
@@ -1640,7 +1697,7 @@ TEST_F(SchedulerTest, MainFrameNotSkippedWhenNoTimingHistory) {
// have history from at least one frame.
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
- scheduler_->ClearHistoryOnNavigation();
+ scheduler_->ClearHistory();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
}
@@ -1660,11 +1717,11 @@ void SchedulerTest::ImplFrameSkippedAfterLateAck(
"ScheduledActionSendBeginMainFrame");
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
@@ -1689,10 +1746,10 @@ void SchedulerTest::ImplFrameSkippedAfterLateAck(
if (receive_ack_before_deadline) {
// It shouldn't matter if the swap ack comes back before the deadline...
scheduler_->DidReceiveCompositorFrameAck();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
} else {
// ... or after the deadline.
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
scheduler_->DidReceiveCompositorFrameAck();
}
EXPECT_NO_ACTION();
@@ -1705,10 +1762,10 @@ void SchedulerTest::ImplFrameSkippedAfterLateAck(
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
}
@@ -1782,7 +1839,7 @@ TEST_F(SchedulerTest,
client_->Reset();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
// Verify we skip every other frame if the swap ack consistently
@@ -1815,7 +1872,7 @@ TEST_F(SchedulerTest,
client_->Reset();
// Deadline should be immediate.
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner().RunUntilTime(now_src_->NowTicks());
+ task_runner_->RunUntilTime(task_runner_->NowTicks());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
}
@@ -1834,11 +1891,11 @@ void SchedulerTest::ImplFrameNotSkippedAfterLateAck() {
"ScheduledActionSendBeginMainFrame");
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
@@ -1858,10 +1915,10 @@ void SchedulerTest::ImplFrameNotSkippedAfterLateAck() {
client_->Reset();
scheduler_->DidReceiveCompositorFrameAck();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
// Verify that we don't skip the actions of the BeginImplFrame
EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame", "ScheduledActionCommit",
@@ -1930,9 +1987,9 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) {
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
@@ -1947,8 +2004,8 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) {
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
@@ -1964,7 +2021,7 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) {
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("WillBeginImplFrame");
// Note: BeginMainFrame and swap are skipped here because of
@@ -1988,7 +2045,7 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) {
SendNextBeginFrame();
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->DidReceiveCompositorFrameAck();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionDrawIfPossible");
@@ -1999,7 +2056,7 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) {
EXPECT_TRUE(scheduler_->NeedsBeginMainFrame());
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
SendNextBeginFrame();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->DidReceiveCompositorFrameAck();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
@@ -2013,10 +2070,10 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) {
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
SendNextBeginFrame();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->DidReceiveCompositorFrameAck();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
@@ -2048,9 +2105,9 @@ TEST_F(
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
EXPECT_FALSE(scheduler_->CommitPending());
@@ -2064,11 +2121,11 @@ TEST_F(
EXPECT_FALSE(scheduler_->CommitPending());
scheduler_->SetNeedsBeginMainFrame();
EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionCommit");
@@ -2080,7 +2137,7 @@ TEST_F(
scheduler_->SetNeedsBeginMainFrame();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->CommitPending());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("WillBeginImplFrame");
}
@@ -2109,10 +2166,10 @@ TEST_F(
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
scheduler_->DidReceiveCompositorFrameAck();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_FALSE(scheduler_->CommitPending());
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
@@ -2127,10 +2184,10 @@ TEST_F(
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
scheduler_->DidReceiveCompositorFrameAck();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionDrawIfPossible");
@@ -2168,7 +2225,7 @@ void SchedulerTest::BeginFramesNotFromClient(BeginFrameSourceType bfs_type) {
client_->Reset();
// NotifyReadyToCommit should trigger the commit.
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
client_->Reset();
@@ -2186,7 +2243,7 @@ void SchedulerTest::BeginFramesNotFromClient(BeginFrameSourceType bfs_type) {
// Make sure SetNeedsBeginFrame isn't called on the client
// when the BeginFrame is no longer needed.
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_NO_ACTION();
client_->Reset();
}
@@ -2222,7 +2279,7 @@ void SchedulerTest::BeginFramesNotFromClient_IsDrawThrottled(
client_->Reset();
// NotifyReadyToCommit should trigger the pending commit.
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
client_->Reset();
@@ -2234,7 +2291,7 @@ void SchedulerTest::BeginFramesNotFromClient_IsDrawThrottled(
// Swapping will put us into a swap throttled state.
// Run posted deadline.
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2251,9 +2308,9 @@ void SchedulerTest::BeginFramesNotFromClient_IsDrawThrottled(
base::TimeTicks before_deadline, after_deadline;
// The deadline is set to the regular deadline.
- before_deadline = now_src()->NowTicks();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
- after_deadline = now_src()->NowTicks();
+ before_deadline = task_runner_->NowTicks();
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
+ after_deadline = task_runner_->NowTicks();
// We can't do an equality comparison here because the scheduler uses a fudge
// factor that's an internal implementation detail.
EXPECT_GT(after_deadline, before_deadline);
@@ -2274,9 +2331,9 @@ void SchedulerTest::BeginFramesNotFromClient_IsDrawThrottled(
client_->Reset();
// The deadline is set to the regular deadline.
- before_deadline = now_src()->NowTicks();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
- after_deadline = now_src()->NowTicks();
+ before_deadline = task_runner_->NowTicks();
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
+ after_deadline = task_runner_->NowTicks();
// We can't do an equality comparison here because the scheduler uses a fudge
// factor that's an internal implementation detail.
EXPECT_GT(after_deadline, before_deadline);
@@ -2328,12 +2385,12 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterBeginFrameStarted) {
EXPECT_NO_ACTION();
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree");
client_->Reset();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
}
@@ -2359,7 +2416,7 @@ TEST_F(SchedulerTest,
client_->Reset();
// Run posted deadline.
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
// OnBeginImplFrameDeadline didn't schedule LayerTreeFrameSink creation
// because
// main frame is not yet completed.
@@ -2368,13 +2425,13 @@ TEST_F(SchedulerTest,
// BeginImplFrame is not started.
client_->Reset();
- task_runner().RunUntilTime(now_src()->NowTicks() +
+ task_runner_->RunUntilTime(task_runner_->NowTicks() +
base::TimeDelta::FromMilliseconds(10));
EXPECT_NO_ACTION();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree",
"ScheduledActionBeginLayerTreeFrameSinkCreation");
@@ -2393,7 +2450,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterReadyToCommit) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
@@ -2404,7 +2461,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterReadyToCommit) {
// RemoveObserver(this) is not called until the end of the frame.
client_->Reset();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
}
@@ -2427,7 +2484,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterSetNeedsPrepareTiles) {
EXPECT_NO_ACTION();
client_->Reset();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionPrepareTiles",
"ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
@@ -2449,7 +2506,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWithDelayBasedBeginFrameSource) {
// NotifyReadyToCommit should trigger the commit.
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
EXPECT_TRUE(scheduler_->begin_frames_expected());
@@ -2467,7 +2524,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWithDelayBasedBeginFrameSource) {
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
EXPECT_FALSE(scheduler_->begin_frames_expected());
}
@@ -2485,7 +2542,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWhenIdle) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
@@ -2494,7 +2551,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWhenIdle) {
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
// Idle time between BeginFrames.
@@ -2517,14 +2574,14 @@ TEST_F(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetVisible(false);
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
// Sync tree should be forced to activate.
EXPECT_ACTIONS("ScheduledActionActivateSyncTree", "RemoveObserver(this)");
@@ -2543,14 +2600,14 @@ TEST_F(SchedulerTest, ScheduledActionActivateAfterBeginFrameSourcePaused) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
fake_external_begin_frame_source_->SetPaused(true);
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
// Sync tree should be forced to activate.
// Pausing the begin frame source aborts the draw. Then
@@ -2573,7 +2630,7 @@ TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottled) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
scheduler_->SetNeedsRedraw();
@@ -2582,13 +2639,13 @@ TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottled) {
client_->Reset();
// Unthrottled frame source will immediately begin a new frame.
- task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ task_runner_->RunPendingTasks(); // Run posted BeginFrame.
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
// If we don't swap on the deadline, we wait for the next BeginFrame.
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2615,14 +2672,14 @@ TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottledBeforeDeadline) {
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
// Unthrottled frame source will immediately begin a new frame.
"WillBeginImplFrame");
scheduler_->SetNeedsRedraw();
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2637,12 +2694,12 @@ TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) {
EXPECT_NO_ACTION();
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ task_runner_->RunPendingTasks(); // Run posted BeginFrame.
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2653,7 +2710,7 @@ TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) {
// SetNeedsRedraw should begin the frame on the next BeginImplFrame.
scheduler_->SetNeedsRedraw();
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
client_->Reset();
@@ -2662,7 +2719,7 @@ TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
}
@@ -2683,7 +2740,7 @@ TEST_F(SchedulerTest, SwitchFrameSourceToNullInsideDeadline) {
client_->Reset();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(scheduler_->begin_frames_expected());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
@@ -2711,7 +2768,7 @@ TEST_F(SchedulerTest, SwitchFrameSourceToNullInsideDeadline) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
}
@@ -2727,7 +2784,7 @@ TEST_F(SchedulerTest, SwitchFrameSourceWhenNotObserving) {
// Begin new frame.
EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
@@ -2743,7 +2800,7 @@ TEST_F(SchedulerTest, SwitchFrameSourceWhenNotObserving) {
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
@@ -2777,7 +2834,7 @@ TEST_F(SchedulerTest, ScheduledActionBeginMainFrameNotExpectedUntil) {
EXPECT_SCOPED(AdvanceFrame());
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionBeginMainFrameNotExpectedUntil",
"ScheduledActionDrawIfPossible");
@@ -2794,10 +2851,10 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Requested) {
// Trigger a frame draw.
EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionCommit", "ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
@@ -2813,7 +2870,7 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Requested) {
// The BeginImplFrame deadline should SetNeedsBeginFrame(false) and send a
// SendBeginMainFrameNotExpectedSoon.
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("RemoveObserver(this)", "SendBeginMainFrameNotExpectedSoon");
client_->Reset();
}
@@ -2830,10 +2887,10 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Unrequested) {
// Trigger a frame draw.
EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionCommit", "ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
@@ -2847,7 +2904,7 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Unrequested) {
// The BeginImplFrame deadline should SetNeedsBeginFrame(false), but doesn't
// send a SendBeginMainFrameNotExpectedSoon as it's not been requested by the
// main thread.
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("RemoveObserver(this)");
client_->Reset();
@@ -2879,7 +2936,9 @@ TEST_F(SchedulerTest, SynchronousCompositorAnimation) {
// Android onDraw. This doesn't consume the single begin frame request.
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ bool skip_draw = false;
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2897,7 +2956,8 @@ TEST_F(SchedulerTest, SynchronousCompositorAnimation) {
// Android onDraw.
scheduler_->SetNeedsRedraw();
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2915,7 +2975,9 @@ TEST_F(SchedulerTest, SynchronousCompositorOnDrawDuringIdle) {
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ bool skip_draw = false;
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
EXPECT_ACTIONS("AddObserver(this)", "ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2975,7 +3037,7 @@ TEST_F(SchedulerTest, AbortEarlyIfNoDamage) {
EXPECT_ACTIONS("AddObserver(this)");
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
// Should not try to schedule a draw. (ScheduledActionDrawIfPossible should
// not appear.)
// When the frame is aborted, the scheduler does not ask for a proactive begin
@@ -2986,10 +3048,56 @@ TEST_F(SchedulerTest, AbortEarlyIfNoDamage) {
scheduler_->SetNeedsRedraw();
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(0, client_->num_draws());
}
+TEST_F(SchedulerTest, SkipDraw) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ SetUpScheduler(EXTERNAL_BFS);
+
+ scheduler_->SetNeedsOneBeginImplFrame();
+ EXPECT_ACTIONS("AddObserver(this)");
+ client_->Reset();
+
+ client_->SetWillBeginImplFrameCausesRedraw(true);
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTIONS("WillBeginImplFrame",
+ "ScheduledActionInvalidateLayerTreeFrameSink");
+ EXPECT_TRUE(client_->invalidate_needs_redraw());
+ client_->Reset();
+
+ // Android onDraw. This doesn't consume the single begin frame request.
+ scheduler_->SetNeedsPrepareTiles();
+ bool resourceless_software_draw = false;
+ bool skip_draw = false;
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
+ EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
+ "ScheduledActionPrepareTiles");
+ client_->Reset();
+
+ // Next vsync.
+ scheduler_->SetNeedsPrepareTiles();
+ AdvanceFrame();
+ EXPECT_ACTIONS("WillBeginImplFrame",
+ "ScheduledActionInvalidateLayerTreeFrameSink");
+ EXPECT_FALSE(client_->invalidate_needs_redraw());
+ client_->Reset();
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->SetNeedsPrepareTiles();
+ client_->SetInvalidateNeedsRedraw(false);
+ skip_draw = true;
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
+ EXPECT_ACTIONS("ScheduledActionPrepareTiles");
+ client_->Reset();
+}
+
TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
@@ -3004,12 +3112,11 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
bool has_damage = false;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_NO_ACTION();
// Next vsync.
@@ -3018,9 +3125,8 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
has_damage = false;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
scheduler_->NotifyReadyToCommit();
@@ -3042,15 +3148,16 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
// filtering this ack (in CompositorExternalBeginFrameSource) and instead
// forwarding the one attached to the later submitted CompositorFrame.
has_damage = false;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
// Android onDraw.
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ bool skip_draw = false;
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -3061,9 +3168,8 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
has_damage = false;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
}
@@ -3098,7 +3204,9 @@ TEST_F(SchedulerTest, SynchronousCompositorPrepareTilesOnDraw) {
// Android onDraw.
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ bool skip_draw = false;
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionPrepareTiles");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
@@ -3107,7 +3215,8 @@ TEST_F(SchedulerTest, SynchronousCompositorPrepareTilesOnDraw) {
// Android onDraw.
scheduler_->SetNeedsRedraw();
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionPrepareTiles");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
@@ -3160,7 +3269,9 @@ TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) {
// Android onDraw.
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ bool skip_draw = false;
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
@@ -3171,7 +3282,7 @@ TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) {
EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
client_->Reset();
@@ -3188,7 +3299,8 @@ TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) {
// Android onDraw.
scheduler_->SetNeedsRedraw();
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
@@ -3208,7 +3320,9 @@ TEST_F(SchedulerTest, SynchronousCompositorResourcelessOnDrawWhenInvisible) {
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = true;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ bool skip_draw = false;
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
// SynchronousCompositor has to draw regardless of visibility.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
@@ -3226,13 +3340,13 @@ TEST_F(SchedulerTest, AuthoritativeVSyncInterval) {
EXPECT_EQ(initial_interval, scheduler_->BeginImplFrameInterval());
- scheduler_->NotifyBeginMainFrameStarted(now_src_->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
scheduler_->NotifyReadyToActivate();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
// Test changing the interval on the frame source external to the scheduler.
- synthetic_frame_source_->OnUpdateVSyncParameters(now_src_->NowTicks(),
+ synthetic_frame_source_->OnUpdateVSyncParameters(task_runner_->NowTicks(),
authoritative_interval);
EXPECT_SCOPED(AdvanceFrame());
@@ -3302,7 +3416,7 @@ TEST_F(SchedulerTest, NoLayerTreeFrameSinkCreationWhileCommitPending) {
// Abort the commit.
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->BeginMainFrameAborted(
CommitEarlyOutReason::ABORTED_LAYER_TREE_FRAME_SINK_LOST);
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
@@ -3337,7 +3451,7 @@ TEST_F(SchedulerTest, ImplSideInvalidationsMergedWithCommit) {
// actions since the impl-side invalidation request will be merged with the
// commit.
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
EXPECT_FALSE(scheduler_->needs_impl_side_invalidation());
@@ -3360,7 +3474,7 @@ TEST_F(SchedulerTest, AbortedCommitsTriggerImplSideInvalidations) {
// should not be blocked on the main frame.
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
EXPECT_ACTIONS("ScheduledActionPerformImplSideInvalidation");
}
@@ -3467,16 +3581,15 @@ TEST_F(SchedulerTest, BeginFrameAckForFinishedImplFrame) {
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
// Successful draw caused damage.
bool has_damage = true;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
// Request another redraw, but fail it. Verify that a new ack is sent.
@@ -3490,7 +3603,7 @@ TEST_F(SchedulerTest, BeginFrameAckForFinishedImplFrame) {
client_->Reset();
client_->SetDrawWillHappen(false);
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
// Failed draw triggers SendBeginMainFrame.
"ScheduledActionSendBeginMainFrame");
@@ -3499,9 +3612,8 @@ TEST_F(SchedulerTest, BeginFrameAckForFinishedImplFrame) {
// Failed draw: no damage.
has_damage = false;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
}
@@ -3523,16 +3635,15 @@ TEST_F(SchedulerTest, BeginFrameAckForSkippedImplFrame) {
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
+ task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
// Successful draw caused damage.
bool has_damage = true;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
// Request another redraw that will be skipped because the swap ack is still
@@ -3547,9 +3658,8 @@ TEST_F(SchedulerTest, BeginFrameAckForSkippedImplFrame) {
// Skipped draw: no damage.
has_damage = false;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
}
@@ -3578,9 +3688,8 @@ TEST_F(SchedulerTest, BeginFrameAckForBeginFrameBeforeLastDeadline) {
// Latest ack should be for the dropped BeginFrame.
bool has_damage = false;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
}
@@ -3610,18 +3719,16 @@ TEST_F(SchedulerTest, BeginFrameAckForDroppedBeginFrame) {
// Latest ack should be for the dropped BeginFrame.
bool has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(second_args.source_id,
- second_args.sequence_number, has_damage),
+ EXPECT_EQ(viz::BeginFrameAck(second_args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
- task_runner().RunPendingTasks(); // Run deadline of prior BeginFrame.
+ task_runner_->RunPendingTasks(); // Run deadline of prior BeginFrame.
EXPECT_ACTIONS("RemoveObserver(this)");
// We'd expect an out-of-order ack for the prior BeginFrame.
has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(first_args.source_id, first_args.sequence_number,
- has_damage),
+ EXPECT_EQ(viz::BeginFrameAck(first_args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
}
@@ -3633,13 +3740,13 @@ TEST_F(SchedulerTest, BeginFrameAckForLateMissedBeginFrame) {
client_->Reset();
// Send a missed BeginFrame with a passed deadline.
- now_src_->Advance(viz::BeginFrameArgs::DefaultInterval());
+ task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
viz::BeginFrameArgs args =
fake_external_begin_frame_source_->CreateBeginFrameArgs(
- BEGINFRAME_FROM_HERE, now_src());
+ BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
args.type = viz::BeginFrameArgs::MISSED;
- now_src_->Advance(viz::BeginFrameArgs::DefaultInterval());
- EXPECT_GT(now_src_->NowTicks(), args.deadline);
+ task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
+ EXPECT_GT(task_runner_->NowTicks(), args.deadline);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_NO_ACTION();
@@ -3648,9 +3755,8 @@ TEST_F(SchedulerTest, BeginFrameAckForLateMissedBeginFrame) {
// Latest ack should be for the missed BeginFrame that was too late: no
// damage.
bool has_damage = false;
- EXPECT_EQ(
- viz::BeginFrameAck(args.source_id, args.sequence_number, has_damage),
- client_->last_begin_frame_ack());
+ EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
+ client_->last_begin_frame_ack());
client_->Reset();
}
@@ -3669,14 +3775,15 @@ TEST_F(SchedulerTest, CriticalBeginMainFrameToActivateIsFast) {
scheduler_->SetNeedsRedraw();
// An interval of 2ms makes sure that the main frame is considered slow.
base::TimeDelta interval = base::TimeDelta::FromMilliseconds(2);
- now_src_->Advance(interval);
+ task_runner_->AdvanceMockTickClock(interval);
viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0u, 1u, now_src_->NowTicks(),
- now_src_->NowTicks() + interval, interval, viz::BeginFrameArgs::NORMAL);
+ BEGINFRAME_FROM_HERE, 0u, 1u, task_runner_->NowTicks(),
+ task_runner_->NowTicks() + interval, interval,
+ viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
- task_runner().RunPendingTasks(); // Run posted deadline to finish the frame.
+ task_runner_->RunPendingTasks(); // Run posted deadline to finish the frame.
ASSERT_FALSE(client_->IsInsideBeginImplFrame());
// Set an interval of 10ms. The bmf_to_activate_interval should be 1*4 = 4ms,
@@ -3685,14 +3792,15 @@ TEST_F(SchedulerTest, CriticalBeginMainFrameToActivateIsFast) {
// the main frame to be activated is 8ms, so it should be considered fast.
scheduler_->SetNeedsRedraw();
interval = base::TimeDelta::FromMilliseconds(10);
- now_src_->Advance(interval);
- args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0u, 2u, now_src_->NowTicks(),
- now_src_->NowTicks() + interval, interval, viz::BeginFrameArgs::NORMAL);
+ task_runner_->AdvanceMockTickClock(interval);
+ args = viz::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, 0u, 2u,
+ task_runner_->NowTicks(),
+ task_runner_->NowTicks() + interval,
+ interval, viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
- task_runner().RunPendingTasks(); // Run posted deadline to finish the frame.
+ task_runner_->RunPendingTasks(); // Run posted deadline to finish the frame.
ASSERT_FALSE(client_->IsInsideBeginImplFrame());
// Increase the draw duration to decrease the time available for the main
@@ -3700,10 +3808,11 @@ TEST_F(SchedulerTest, CriticalBeginMainFrameToActivateIsFast) {
scheduler_->SetNeedsRedraw();
fake_compositor_timing_history_->SetDrawDurationEstimate(
base::TimeDelta::FromMilliseconds(7));
- now_src_->Advance(interval);
- args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0u, 3u, now_src_->NowTicks(),
- now_src_->NowTicks() + interval, interval, viz::BeginFrameArgs::NORMAL);
+ task_runner_->AdvanceMockTickClock(interval);
+ args = viz::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, 0u, 3u,
+ task_runner_->NowTicks(),
+ task_runner_->NowTicks() + interval,
+ interval, viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
}
@@ -3726,10 +3835,11 @@ TEST_F(SchedulerTest, WaitForAllPipelineStagesSkipsMissedBeginFrames) {
client_->Reset();
base::TimeDelta interval = base::TimeDelta::FromMilliseconds(16);
- now_src_->Advance(interval);
+ task_runner_->AdvanceMockTickClock(interval);
viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0u, 1u, now_src_->NowTicks(),
- now_src_->NowTicks() + interval, interval, viz::BeginFrameArgs::MISSED);
+ 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());
}
@@ -3755,10 +3865,10 @@ TEST_F(
// Uses MISSED BeginFrames even after the deadline has passed.
base::TimeDelta interval = base::TimeDelta::FromMilliseconds(16);
- now_src_->Advance(interval);
- base::TimeTicks timestamp = now_src_->NowTicks();
+ task_runner_->AdvanceMockTickClock(interval);
+ base::TimeTicks timestamp = task_runner_->NowTicks();
// Deadline should have passed after this.
- now_src_->Advance(interval * 2);
+ task_runner_->AdvanceMockTickClock(interval * 2);
viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, 0u, 1u, timestamp, timestamp + interval, interval,
viz::BeginFrameArgs::MISSED);
@@ -3792,8 +3902,8 @@ TEST_F(SchedulerTest, WaitForAllPipelineStagesAlwaysObservesBeginFrames) {
// Scheduler begins a frame even if otherwise idle.
base::TimeDelta interval = base::TimeDelta::FromMilliseconds(16);
- now_src_->Advance(interval);
- base::TimeTicks timestamp = now_src_->NowTicks();
+ task_runner_->AdvanceMockTickClock(interval);
+ base::TimeTicks timestamp = task_runner_->NowTicks();
viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, 0u, 1u, timestamp, timestamp + interval, interval,
viz::BeginFrameArgs::NORMAL);
@@ -3803,7 +3913,7 @@ TEST_F(SchedulerTest, WaitForAllPipelineStagesAlwaysObservesBeginFrames) {
client_->Reset();
// BeginFrame deadline is blocked because commits are deferred.
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
EXPECT_ACTIONS();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -3886,7 +3996,7 @@ TEST_F(SchedulerTest, SlowMainThreadButEstimatedFastTriggersInvalidations) {
// Draw deadline.
client_->Reset();
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
EXPECT_ACTIONS();
// Next frame. The invalidation should not be throttled.
@@ -3910,13 +4020,13 @@ TEST_F(SchedulerTest,
// Commit before deadline but not ready to activate.
client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(now_src_->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("ScheduledActionCommit");
// Draw deadline.
client_->Reset();
- task_runner().RunPendingTasks();
+ task_runner_->RunPendingTasks();
EXPECT_ACTIONS();
// Next frame. The invalidation should still be throttled.
@@ -3949,7 +4059,7 @@ TEST_F(SchedulerTest, DontSkipMainFrameAfterClearingHistory) {
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_SCOPED(AdvanceFrame());
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame");
@@ -3959,14 +4069,14 @@ TEST_F(SchedulerTest, DontSkipMainFrameAfterClearingHistory) {
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->SetNeedsBeginMainFrame();
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
+ scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionCommit");
// But during the commit, the history is cleared. So the main frame should not
// be skipped.
client_->Reset();
- scheduler_->ClearHistoryOnNavigation();
+ scheduler_->ClearHistory();
EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
}
diff --git a/chromium/cc/tiles/frame_viewer_instrumentation.cc b/chromium/cc/tiles/frame_viewer_instrumentation.cc
index a40ad5ba365..09ac5b6857d 100644
--- a/chromium/cc/tiles/frame_viewer_instrumentation.cc
+++ b/chromium/cc/tiles/frame_viewer_instrumentation.cc
@@ -10,9 +10,8 @@ namespace cc {
namespace frame_viewer_instrumentation {
const char kCategoryLayerTree[] =
- TRACE_DISABLED_BY_DEFAULT("cc.debug") ","
- TRACE_DISABLED_BY_DEFAULT("cc.debug.quads") ","
- TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers");
+ TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
+ "viz.quads") "," TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers");
namespace {
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc
index efac77afbf7..747f1a367a9 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache.cc
@@ -111,17 +111,46 @@ int CalculateUploadScaleMipLevel(const DrawImage& draw_image) {
// Calculates the scale factor which can be used to scale an image to a given
// mip level.
SkSize CalculateScaleFactorForMipLevel(const DrawImage& draw_image,
- int mip_level) {
+ int upload_scale_mip_level) {
gfx::Size base_size(draw_image.paint_image().width(),
draw_image.paint_image().height());
- return MipMapUtil::GetScaleAdjustmentForLevel(base_size, mip_level);
+ return MipMapUtil::GetScaleAdjustmentForLevel(base_size,
+ upload_scale_mip_level);
}
// Calculates the size of a given mip level.
-gfx::Size CalculateSizeForMipLevel(const DrawImage& draw_image, int mip_level) {
+gfx::Size CalculateSizeForMipLevel(const DrawImage& draw_image,
+ int upload_scale_mip_level) {
gfx::Size base_size(draw_image.paint_image().width(),
draw_image.paint_image().height());
- return MipMapUtil::GetSizeForLevel(base_size, mip_level);
+ return MipMapUtil::GetSizeForLevel(base_size, upload_scale_mip_level);
+}
+
+// Determines whether a draw image requires mips.
+bool ShouldGenerateMips(const DrawImage& draw_image,
+ int upload_scale_mip_level) {
+ // If filter quality is less than medium, don't generate mips.
+ if (draw_image.filter_quality() < kMedium_SkFilterQuality)
+ return false;
+
+ gfx::Size base_size(draw_image.paint_image().width(),
+ draw_image.paint_image().height());
+ // Take the abs of the scale, as mipmap functions don't handle (and aren't
+ // impacted by) negative image dimensions.
+ gfx::SizeF scaled_size = gfx::ScaleSize(
+ gfx::SizeF(base_size), std::abs(draw_image.scale().width()),
+ std::abs(draw_image.scale().height()));
+
+ // If our target size is smaller than our scaled size in both dimension, we
+ // need to generate mips.
+ gfx::SizeF target_size =
+ gfx::SizeF(CalculateSizeForMipLevel(draw_image, upload_scale_mip_level));
+ if (scaled_size.width() < target_size.width() &&
+ scaled_size.height() < target_size.height()) {
+ return true;
+ }
+
+ return false;
}
// Draws and scales the provided |draw_image| into the |target_pixmap|. If the
@@ -138,19 +167,32 @@ bool DrawAndScaleImage(const DrawImage& draw_image, SkPixmap* target_pixmap) {
sk_sp<SkColorSpace> color_space = target_pixmap->info().refColorSpace();
const PaintImage& paint_image = draw_image.paint_image();
+ const bool is_original_decode =
+ SkISize::Make(paint_image.width(), paint_image.height()) ==
+ pixmap.bounds().size();
+ const bool is_nearest_neighbor =
+ draw_image.filter_quality() == kNone_SkFilterQuality;
+
SkISize supported_size =
paint_image.GetSupportedDecodeSize(pixmap.bounds().size());
-
- if (supported_size == pixmap.bounds().size()) {
+ // We can directly decode into target pixmap if we are doing an original
+ // decode or we are decoding to scale without nearest neighbor filtering.
+ const bool can_directly_decode = is_original_decode || !is_nearest_neighbor;
+ if (supported_size == pixmap.bounds().size() && can_directly_decode) {
SkImageInfo info = pixmap.info();
return paint_image.Decode(pixmap.writable_addr(), &info, color_space,
draw_image.frame_index());
}
// If we can't decode/scale directly, we will handle this in up to 3 steps.
- // Step 1: Decode at the nearest (larger) directly supported size.
- SkImageInfo decode_info = SkImageInfo::MakeN32Premul(supported_size.width(),
- supported_size.height());
+ // Step 1: Decode at the nearest (larger) directly supported size or the
+ // original size if nearest neighbor quality is requested.
+ SkISize decode_size =
+ is_nearest_neighbor
+ ? SkISize::Make(paint_image.width(), paint_image.height())
+ : supported_size;
+ SkImageInfo decode_info =
+ SkImageInfo::MakeN32Premul(decode_size.width(), decode_size.height());
SkBitmap decode_bitmap;
if (!decode_bitmap.tryAllocPixels(decode_info))
return false;
@@ -185,21 +227,6 @@ bool DrawAndScaleImage(const DrawImage& draw_image, SkPixmap* target_pixmap) {
return scaled_pixmap.readPixels(pixmap);
}
-// Returns the GL texture ID backing the given SkImage.
-GrGLuint GlIdFromSkImage(SkImage* image) {
- DCHECK(image->isTextureBacked());
- GrBackendTexture backend_texture =
- image->getBackendTexture(true /* flushPendingGrContextIO */);
- if (!backend_texture.isValid())
- return 0;
-
- GrGLTextureInfo info;
- if (!backend_texture.getGLTextureInfo(&info))
- return 0;
-
- return info.fID;
-}
-
// Takes ownership of the backing texture of an SkImage. This allows us to
// delete this texture under Skia (via discardable).
sk_sp<SkImage> TakeOwnershipOfSkImageBacking(GrContext* context,
@@ -238,11 +265,49 @@ void DeleteSkImageAndPreventCaching(viz::RasterContextProvider* context,
if (image_owned) {
// Delete |original_image_owned| as Skia will not clean it up. We are
// holding the context lock here, so we can delete immediately.
- uint32_t texture_id = GlIdFromSkImage(image_owned.get());
+ uint32_t texture_id =
+ GpuImageDecodeCache::GlIdFromSkImage(image_owned.get());
context->ContextGL()->DeleteTextures(1, &texture_id);
}
}
+// TODO(ericrk): Replace calls to this with calls to SkImage::makeTextureImage,
+// once that function handles colorspaces. https://crbug.com/834837
+sk_sp<SkImage> MakeTextureImage(viz::RasterContextProvider* context,
+ sk_sp<SkImage> source_image,
+ sk_sp<SkColorSpace> target_color_space,
+ GrMipMapped mip_mapped) {
+ // Step 1: Upload image and generate mips if necessary. If we will be applying
+ // a color-space conversion, don't generate mips yet, instead do it after
+ // conversion, in step 3.
+ bool add_mips_after_color_conversion =
+ (target_color_space && mip_mapped == GrMipMapped::kYes);
+ sk_sp<SkImage> uploaded_image = source_image->makeTextureImage(
+ context->GrContext(), nullptr,
+ add_mips_after_color_conversion ? GrMipMapped::kNo : mip_mapped);
+
+ // Step 2: Apply a color-space conversion if necessary.
+ if (uploaded_image && target_color_space) {
+ sk_sp<SkImage> pre_converted_image = uploaded_image;
+ uploaded_image = uploaded_image->makeColorSpace(target_color_space);
+
+ if (uploaded_image != pre_converted_image)
+ DeleteSkImageAndPreventCaching(context, std::move(pre_converted_image));
+ }
+
+ // Step 3: If we had a colorspace conversion, we couldn't mipmap in step 1, so
+ // add mips here.
+ if (uploaded_image && add_mips_after_color_conversion) {
+ sk_sp<SkImage> pre_mipped_image = uploaded_image;
+ uploaded_image = uploaded_image->makeTextureImage(
+ context->GrContext(), nullptr, GrMipMapped::kYes);
+ DCHECK_NE(pre_mipped_image, uploaded_image);
+ DeleteSkImageAndPreventCaching(context, std::move(pre_mipped_image));
+ }
+
+ return uploaded_image;
+}
+
} // namespace
// static
@@ -255,13 +320,14 @@ GpuImageDecodeCache::InUseCacheKey::FromDrawImage(const DrawImage& draw_image) {
// the |in_use_cache_|.
GpuImageDecodeCache::InUseCacheKey::InUseCacheKey(const DrawImage& draw_image)
: frame_key(draw_image.frame_key()),
- mip_level(CalculateUploadScaleMipLevel(draw_image)),
+ upload_scale_mip_level(CalculateUploadScaleMipLevel(draw_image)),
filter_quality(CalculateDesiredFilterQuality(draw_image)),
target_color_space(draw_image.target_color_space()) {}
bool GpuImageDecodeCache::InUseCacheKey::operator==(
const InUseCacheKey& other) const {
- return frame_key == other.frame_key && mip_level == other.mip_level &&
+ return frame_key == other.frame_key &&
+ upload_scale_mip_level == other.upload_scale_mip_level &&
filter_quality == other.filter_quality &&
target_color_space == other.target_color_space;
}
@@ -270,9 +336,9 @@ size_t GpuImageDecodeCache::InUseCacheKeyHash::operator()(
const InUseCacheKey& cache_key) const {
return base::HashInts(
cache_key.target_color_space.GetHash(),
- base::HashInts(
- cache_key.frame_key.hash(),
- base::HashInts(cache_key.mip_level, cache_key.filter_quality)));
+ base::HashInts(cache_key.frame_key.hash(),
+ base::HashInts(cache_key.upload_scale_mip_level,
+ cache_key.filter_quality)));
}
GpuImageDecodeCache::InUseCacheEntry::InUseCacheEntry(
@@ -530,17 +596,21 @@ void GpuImageDecodeCache::UploadedImageData::ReportUsageStats() const {
}
GpuImageDecodeCache::ImageData::ImageData(
+ PaintImage::Id paint_image_id,
DecodedDataMode mode,
size_t size,
const gfx::ColorSpace& target_color_space,
SkFilterQuality quality,
- int mip_level,
+ int upload_scale_mip_level,
+ bool needs_mips,
bool is_bitmap_backed)
- : mode(mode),
+ : paint_image_id(paint_image_id),
+ mode(mode),
size(size),
target_color_space(target_color_space),
quality(quality),
- mip_level(mip_level),
+ upload_scale_mip_level(upload_scale_mip_level),
+ needs_mips(needs_mips),
is_bitmap_backed(is_bitmap_backed),
decode(is_bitmap_backed) {}
@@ -563,7 +633,7 @@ bool GpuImageDecodeCache::ImageData::IsGpuOrTransferCache() const {
bool GpuImageDecodeCache::ImageData::HasUploadedData() const {
switch (mode) {
case DecodedDataMode::kGpu:
- return upload.image();
+ return !!upload.image();
case DecodedDataMode::kTransferCache:
return !!upload.transfer_cache_id();
case DecodedDataMode::kCpu:
@@ -578,6 +648,21 @@ void GpuImageDecodeCache::ImageData::ValidateBudgeted() const {
DCHECK_GT(upload.ref_count, 0u);
}
+// static
+GrGLuint GpuImageDecodeCache::GlIdFromSkImage(const SkImage* image) {
+ DCHECK(image->isTextureBacked());
+ GrBackendTexture backend_texture =
+ image->getBackendTexture(true /* flushPendingGrContextIO */);
+ if (!backend_texture.isValid())
+ return 0;
+
+ GrGLTextureInfo info;
+ if (!backend_texture.getGLTextureInfo(&info))
+ return 0;
+
+ return info.fID;
+}
+
GpuImageDecodeCache::GpuImageDecodeCache(viz::RasterContextProvider* context,
bool use_transfer_cache,
SkColorType color_type,
@@ -613,6 +698,10 @@ GpuImageDecodeCache::~GpuImageDecodeCache() {
// Unregister this component with memory_coordinator::ClientRegistry.
base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
+ memory_pressure_listener_.reset(
+ new base::MemoryPressureListener(base::BindRepeating(
+ &GpuImageDecodeCache::OnMemoryPressure, base::Unretained(this))));
+
// TODO(vmpstr): If we don't have a client name, it may cause problems in
// unittests, since most tests don't set the name but some do. The UMA system
// expects the name to be always the same. This assertion is violated in the
@@ -651,8 +740,8 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
return TaskResult(false);
base::AutoLock lock(lock_);
- const PaintImage::FrameKey frame_key = draw_image.frame_key();
- ImageData* image_data = GetImageDataForDrawImage(draw_image);
+ const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
+ ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
scoped_refptr<ImageData> new_data;
if (!image_data) {
// We need an ImageData, create one now.
@@ -665,13 +754,13 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
image_data->upload.task) {
// We had an existing upload task, ref the image and return the task.
image_data->ValidateBudgeted();
- RefImage(draw_image);
+ RefImage(draw_image, cache_key);
return TaskResult(image_data->upload.task);
} else if (task_type == DecodeTaskType::kStandAloneDecodeTask &&
image_data->decode.stand_alone_task) {
// We had an existing out of raster task, ref the image and return the task.
image_data->ValidateBudgeted();
- RefImage(draw_image);
+ RefImage(draw_image, cache_key);
return TaskResult(image_data->decode.stand_alone_task);
}
@@ -685,11 +774,11 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
// If we had to create new image data, add it to our map now that we know it
// will fit.
if (new_data)
- persistent_cache_.Put(frame_key, std::move(new_data));
+ AddToPersistentCache(draw_image, std::move(new_data));
// Ref the image before creating a task - this ref is owned by the caller, and
// it is their responsibility to release it by calling UnrefImage.
- RefImage(draw_image);
+ RefImage(draw_image, cache_key);
// If we already have an image and it is locked (or lock-able), just return
// that. The image must be budgeted before we attempt to lock it.
@@ -703,7 +792,7 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
if (task_type == DecodeTaskType::kPartOfUploadTask) {
// Ref image and create a upload and decode tasks. We will release this ref
// in UploadTaskCompleted.
- RefImage(draw_image);
+ RefImage(draw_image, cache_key);
task = base::MakeRefCounted<ImageUploadTaskImpl>(
this, draw_image,
GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type),
@@ -720,7 +809,15 @@ void GpuImageDecodeCache::UnrefImage(const DrawImage& draw_image) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::UnrefImage");
base::AutoLock lock(lock_);
- UnrefImageInternal(draw_image);
+ UnrefImageInternal(draw_image, InUseCacheKey::FromDrawImage(draw_image));
+}
+
+bool GpuImageDecodeCache::UseCacheForDrawImage(
+ const DrawImage& draw_image) const {
+ if (draw_image.paint_image().GetSkImage()->isTextureBacked())
+ return false;
+
+ return true;
}
DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
@@ -736,20 +833,21 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
return DecodedDrawImage();
base::AutoLock lock(lock_);
- ImageData* image_data = GetImageDataForDrawImage(draw_image);
+ const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
+ ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
if (!image_data) {
// We didn't find the image, create a new entry.
auto data = CreateImageData(draw_image);
image_data = data.get();
- persistent_cache_.Put(draw_image.frame_key(), std::move(data));
+ AddToPersistentCache(draw_image, std::move(data));
}
// Ref the image and decode so that they stay alive while we are
// decoding/uploading.
// Note that refing the image will attempt to budget the image, if not already
// done.
- RefImage(draw_image);
- RefImageDecode(draw_image);
+ RefImage(draw_image, cache_key);
+ RefImageDecode(draw_image, cache_key);
// 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.
@@ -757,7 +855,7 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
UploadImageIfNecessary(draw_image, image_data);
// Unref the image decode, but not the image. The image ref will be released
// in DrawWithImageFinished.
- UnrefImageDecode(draw_image);
+ UnrefImageDecode(draw_image, cache_key);
if (image_data->mode == DecodedDataMode::kTransferCache) {
DCHECK(use_transfer_cache_);
@@ -766,11 +864,11 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
image_data->upload.mark_used();
DCHECK(id || image_data->decode.decode_failure);
- SkSize scale_factor =
- CalculateScaleFactorForMipLevel(draw_image, image_data->mip_level);
+ SkSize scale_factor = CalculateScaleFactorForMipLevel(
+ draw_image, image_data->upload_scale_mip_level);
DecodedDrawImage decoded_draw_image(
id, SkSize(), scale_factor, CalculateDesiredFilterQuality(draw_image),
- image_data->is_budgeted);
+ image_data->needs_mips, image_data->is_budgeted);
return decoded_draw_image;
} else {
DCHECK(!use_transfer_cache_);
@@ -779,8 +877,8 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
image_data->upload.mark_used();
DCHECK(image || image_data->decode.decode_failure);
- SkSize scale_factor =
- CalculateScaleFactorForMipLevel(draw_image, image_data->mip_level);
+ SkSize scale_factor = CalculateScaleFactorForMipLevel(
+ draw_image, image_data->upload_scale_mip_level);
DecodedDrawImage decoded_draw_image(
std::move(image), SkSize(), scale_factor,
CalculateDesiredFilterQuality(draw_image), image_data->is_budgeted);
@@ -805,7 +903,7 @@ void GpuImageDecodeCache::DrawWithImageFinished(
return;
base::AutoLock lock(lock_);
- UnrefImageInternal(draw_image);
+ UnrefImageInternal(draw_image, InUseCacheKey::FromDrawImage(draw_image));
// We are mid-draw and holding the context lock, ensure we clean up any
// textures (especially at-raster), which may have just been marked for
@@ -862,8 +960,16 @@ void GpuImageDecodeCache::ClearCache() {
paint_image_entries_.clear();
}
-GpuImageDecodeCache::PersistentCache::iterator
-GpuImageDecodeCache::RemoveFromPersistentCache(PersistentCache::iterator it) {
+void GpuImageDecodeCache::AddToPersistentCache(const DrawImage& draw_image,
+ scoped_refptr<ImageData> data) {
+ lock_.AssertAcquired();
+
+ WillAddCacheEntry(draw_image);
+ persistent_cache_.Put(draw_image.frame_key(), std::move(data));
+}
+
+template <typename Iterator>
+Iterator GpuImageDecodeCache::RemoveFromPersistentCache(Iterator it) {
lock_.AssertAcquired();
if (it->second->decode.ref_count != 0 || it->second->upload.ref_count != 0) {
@@ -883,6 +989,15 @@ GpuImageDecodeCache::RemoveFromPersistentCache(PersistentCache::iterator it) {
DeleteImage(it->second.get());
}
+ auto entries_it = paint_image_entries_.find(it->second->paint_image_id);
+ DCHECK(entries_it != paint_image_entries_.end());
+ DCHECK_GT(entries_it->second.count, 0u);
+
+ // If this is the last entry for this image, remove its tracking.
+ --entries_it->second.count;
+ if (entries_it->second.count == 0u)
+ paint_image_entries_.erase(entries_it);
+
return persistent_cache_.Erase(it);
}
@@ -981,7 +1096,8 @@ void GpuImageDecodeCache::DecodeImageInTask(const DrawImage& draw_image,
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::DecodeImage");
base::AutoLock lock(lock_);
- ImageData* image_data = GetImageDataForDrawImage(draw_image);
+ ImageData* image_data = GetImageDataForDrawImage(
+ draw_image, InUseCacheKey::FromDrawImage(draw_image));
DCHECK(image_data);
DCHECK(image_data->is_budgeted) << "Must budget an image for pre-decoding";
DecodeImageIfNecessary(draw_image, image_data, task_type);
@@ -996,7 +1112,8 @@ void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) {
context_lock.emplace(context_);
base::AutoLock lock(lock_);
- ImageData* image_data = GetImageDataForDrawImage(draw_image);
+ ImageData* image_data = GetImageDataForDrawImage(
+ draw_image, InUseCacheKey::FromDrawImage(draw_image));
DCHECK(image_data);
DCHECK(image_data->is_budgeted) << "Must budget an image for pre-decoding";
UploadImageIfNecessary(draw_image, image_data);
@@ -1008,8 +1125,9 @@ void GpuImageDecodeCache::OnImageDecodeTaskCompleted(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::OnImageDecodeTaskCompleted");
base::AutoLock lock(lock_);
+ auto cache_key = InUseCacheKey::FromDrawImage(draw_image);
// Decode task is complete, remove our reference to it.
- ImageData* image_data = GetImageDataForDrawImage(draw_image);
+ ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
DCHECK(image_data);
if (task_type == DecodeTaskType::kPartOfUploadTask) {
DCHECK(image_data->decode.task);
@@ -1022,7 +1140,7 @@ void GpuImageDecodeCache::OnImageDecodeTaskCompleted(
// While the decode task is active, we keep a ref on the decoded data.
// Release that ref now.
- UnrefImageDecode(draw_image);
+ UnrefImageDecode(draw_image, cache_key);
}
void GpuImageDecodeCache::OnImageUploadTaskCompleted(
@@ -1031,7 +1149,8 @@ void GpuImageDecodeCache::OnImageUploadTaskCompleted(
"GpuImageDecodeCache::OnImageUploadTaskCompleted");
base::AutoLock lock(lock_);
// Upload task is complete, remove our reference to it.
- ImageData* image_data = GetImageDataForDrawImage(draw_image);
+ InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
+ ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
DCHECK(image_data);
DCHECK(image_data->upload.task);
image_data->upload.task = nullptr;
@@ -1039,8 +1158,8 @@ void GpuImageDecodeCache::OnImageUploadTaskCompleted(
// While the upload task is active, we keep a ref on both the image it will be
// populating, as well as the decode it needs to populate it. Release these
// refs now.
- UnrefImageDecode(draw_image);
- UnrefImageInternal(draw_image);
+ UnrefImageDecode(draw_image, cache_key);
+ UnrefImageInternal(draw_image, cache_key);
}
// Checks if an existing image decode exists. If not, returns a task to produce
@@ -1053,12 +1172,14 @@ scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef(
"GpuImageDecodeCache::GetImageDecodeTaskAndRef");
lock_.AssertAcquired();
+ auto cache_key = InUseCacheKey::FromDrawImage(draw_image);
+
// This ref is kept alive while an upload task may need this decode. We
// release this ref in UploadTaskCompleted.
if (task_type == DecodeTaskType::kPartOfUploadTask)
- RefImageDecode(draw_image);
+ RefImageDecode(draw_image, cache_key);
- ImageData* image_data = GetImageDataForDrawImage(draw_image);
+ ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
DCHECK(image_data);
if (image_data->decode.is_locked()) {
// We should never be creating a decode task for a not budgeted image.
@@ -1076,29 +1197,31 @@ scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef(
if (!existing_task) {
// Ref image decode and create a decode task. This ref will be released in
// DecodeTaskCompleted.
- RefImageDecode(draw_image);
+ RefImageDecode(draw_image, cache_key);
existing_task = base::MakeRefCounted<GpuImageDecodeTaskImpl>(
this, draw_image, tracing_info, task_type);
}
return existing_task;
}
-void GpuImageDecodeCache::RefImageDecode(const DrawImage& draw_image) {
+void GpuImageDecodeCache::RefImageDecode(const DrawImage& draw_image,
+ const InUseCacheKey& cache_key) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::RefImageDecode");
lock_.AssertAcquired();
- auto found = in_use_cache_.find(InUseCacheKey::FromDrawImage(draw_image));
+ auto found = in_use_cache_.find(cache_key);
DCHECK(found != in_use_cache_.end());
++found->second.ref_count;
++found->second.image_data->decode.ref_count;
OwnershipChanged(draw_image, found->second.image_data.get());
}
-void GpuImageDecodeCache::UnrefImageDecode(const DrawImage& draw_image) {
+void GpuImageDecodeCache::UnrefImageDecode(const DrawImage& draw_image,
+ const InUseCacheKey& cache_key) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::UnrefImageDecode");
lock_.AssertAcquired();
- auto found = in_use_cache_.find(InUseCacheKey::FromDrawImage(draw_image));
+ auto found = in_use_cache_.find(cache_key);
DCHECK(found != in_use_cache_.end());
DCHECK_GT(found->second.image_data->decode.ref_count, 0u);
DCHECK_GT(found->second.ref_count, 0u);
@@ -1110,12 +1233,12 @@ void GpuImageDecodeCache::UnrefImageDecode(const DrawImage& draw_image) {
}
}
-void GpuImageDecodeCache::RefImage(const DrawImage& draw_image) {
+void GpuImageDecodeCache::RefImage(const DrawImage& draw_image,
+ const InUseCacheKey& cache_key) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::RefImage");
lock_.AssertAcquired();
- InUseCacheKey key = InUseCacheKey::FromDrawImage(draw_image);
- auto found = in_use_cache_.find(key);
+ auto found = in_use_cache_.find(cache_key);
// If no secondary cache entry was found for the given |draw_image|, then
// the draw_image only exists in the |persistent_cache_|. Create an in-use
@@ -1126,7 +1249,7 @@ void GpuImageDecodeCache::RefImage(const DrawImage& draw_image) {
DCHECK(IsCompatible(found_image->second.get(), draw_image));
found = in_use_cache_
.insert(InUseCache::value_type(
- key, InUseCacheEntry(found_image->second)))
+ cache_key, InUseCacheEntry(found_image->second)))
.first;
}
@@ -1136,9 +1259,10 @@ void GpuImageDecodeCache::RefImage(const DrawImage& draw_image) {
OwnershipChanged(draw_image, found->second.image_data.get());
}
-void GpuImageDecodeCache::UnrefImageInternal(const DrawImage& draw_image) {
+void GpuImageDecodeCache::UnrefImageInternal(const DrawImage& draw_image,
+ const InUseCacheKey& cache_key) {
lock_.AssertAcquired();
- auto found = in_use_cache_.find(InUseCacheKey::FromDrawImage(draw_image));
+ auto found = in_use_cache_.find(cache_key);
DCHECK(found != in_use_cache_.end());
DCHECK_GT(found->second.image_data->upload.ref_count, 0u);
DCHECK_GT(found->second.ref_count, 0u);
@@ -1158,6 +1282,12 @@ void GpuImageDecodeCache::OwnershipChanged(const DrawImage& draw_image,
bool has_any_refs =
image_data->upload.ref_count > 0 || image_data->decode.ref_count > 0;
+ // If we have no image refs on an image, we should unbudget it.
+ if (!has_any_refs && image_data->is_budgeted) {
+ DCHECK_GE(working_set_bytes_, image_data->size);
+ working_set_bytes_ -= image_data->size;
+ image_data->is_budgeted = false;
+ }
// Don't keep around completely empty images. This can happen if an image's
// decode/upload tasks were both cancelled before completing.
@@ -1168,7 +1298,7 @@ void GpuImageDecodeCache::OwnershipChanged(const DrawImage& draw_image,
!image_data->is_orphaned) {
auto found_persistent = persistent_cache_.Peek(draw_image.frame_key());
if (found_persistent != persistent_cache_.end())
- persistent_cache_.Erase(found_persistent);
+ RemoveFromPersistentCache(found_persistent);
}
// If we have no refs on an uploaded image, it should be unlocked. Do this
@@ -1197,13 +1327,6 @@ void GpuImageDecodeCache::OwnershipChanged(const DrawImage& draw_image,
image_data->is_budgeted = true;
}
- // If we have no image refs on an image, we should unbudget it.
- if (!has_any_refs && image_data->is_budgeted) {
- DCHECK_GE(working_set_bytes_, image_data->size);
- working_set_bytes_ -= image_data->size;
- image_data->is_budgeted = false;
- }
-
// We should unlock the decoded image memory for the image in two cases:
// 1) The image is no longer being used (no decode or upload refs).
// 2) This is a non-CPU image that has already been uploaded and we have
@@ -1256,18 +1379,7 @@ bool GpuImageDecodeCache::EnsureCapacity(size_t required_size) {
continue;
}
- // Current entry has no refs. Ensure it is not locked.
- DCHECK(!it->second->decode.is_locked());
- DCHECK(!it->second->upload.is_locked());
-
- // Unlocked images must not be budgeted.
- DCHECK(!it->second->is_budgeted);
-
- // Free the uploaded image if it exists.
- if (it->second->HasUploadedData())
- DeleteImage(it->second.get());
-
- it = persistent_cache_.Erase(it);
+ it = RemoveFromPersistentCache(it);
}
return CanFitInWorkingSet(required_size);
@@ -1330,7 +1442,7 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
}
TRACE_EVENT0("cc", "GpuImageDecodeCache::DecodeImage");
- RecordImageMipLevelUMA(image_data->mip_level);
+ RecordImageMipLevelUMA(image_data->upload_scale_mip_level);
image_data->decode.ResetData();
std::unique_ptr<base::DiscardableMemory> backing_memory;
@@ -1339,8 +1451,8 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
base::AutoUnlock unlock(lock_);
backing_memory = base::DiscardableMemoryAllocator::GetInstance()
->AllocateLockedDiscardableMemory(image_data->size);
- SkImageInfo image_info =
- CreateImageInfoForDrawImage(draw_image, image_data->mip_level);
+ SkImageInfo image_info = CreateImageInfoForDrawImage(
+ draw_image, image_data->upload_scale_mip_level);
SkPixmap pixmap(image_info, backing_memory->data(),
image_info.minRowBytes());
@@ -1389,38 +1501,60 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
return;
}
- if (image_data->HasUploadedData() &&
- TryLockImage(HaveContextLock::kYes, draw_image, image_data)) {
- // Someone has uploaded this image before us (at raster).
+ // If an upload already exists, try to lock it. If this fails, it will clear
+ // any uploaded data.
+ if (image_data->HasUploadedData())
+ TryLockImage(HaveContextLock::kYes, draw_image, image_data);
+
+ // Ensure the mip status is correct before returning the locked upload or
+ // preparing to upload a new image.
+ UpdateMipsIfNeeded(draw_image, image_data);
+
+ // If we have uploaded data at this point, it is locked with correct mips,
+ // just return.
+ if (image_data->HasUploadedData())
return;
- }
TRACE_EVENT0("cc", "GpuImageDecodeCache::UploadImage");
DCHECK(image_data->decode.is_locked());
DCHECK_GT(image_data->decode.ref_count, 0u);
DCHECK_GT(image_data->upload.ref_count, 0u);
+ sk_sp<SkColorSpace> target_color_space =
+ SupportsColorSpaceConversion() &&
+ draw_image.target_color_space().IsValid()
+ ? draw_image.target_color_space().ToSkColorSpace()
+ : nullptr;
+ if (target_color_space &&
+ SkColorSpace::Equals(target_color_space.get(),
+ image_data->decode.image()->colorSpace())) {
+ target_color_space = nullptr;
+ }
+
if (image_data->mode == DecodedDataMode::kTransferCache) {
DCHECK(use_transfer_cache_);
SkPixmap pixmap;
if (!image_data->decode.image()->peekPixels(&pixmap))
return;
- sk_sp<SkColorSpace> color_space =
- SupportsColorSpaceConversion()
- ? draw_image.target_color_space().ToSkColorSpace()
- : nullptr;
- ClientImageTransferCacheEntry image_entry(&pixmap, color_space.get());
+ ClientImageTransferCacheEntry image_entry(&pixmap, target_color_space.get(),
+ image_data->needs_mips);
size_t size = image_entry.SerializedSize();
void* data = context_->ContextSupport()->MapTransferCacheEntry(size);
- // TODO(piman): handle error (failed to allocate/map shm)
- DCHECK(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());
+ 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;
+ }
return;
}
@@ -1437,50 +1571,40 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
if (image_data->mode == DecodedDataMode::kGpu) {
DCHECK(!use_transfer_cache_);
base::AutoUnlock unlock(lock_);
- uploaded_image =
- uploaded_image->makeTextureImage(context_->GrContext(), nullptr);
-
- if (uploaded_image && SupportsColorSpaceConversion() &&
- draw_image.target_color_space().IsValid()) {
- TRACE_EVENT0("cc", "GpuImageDecodeCache::UploadImage - color conversion");
- sk_sp<SkImage> pre_converted_image = uploaded_image;
- uploaded_image = uploaded_image->makeColorSpace(
- draw_image.target_color_space().ToSkColorSpace(),
- SkTransferFunctionBehavior::kIgnore);
-
- // If we created a new image while converting colorspace, we should
- // destroy the previous image without caching it.
- if (uploaded_image != pre_converted_image)
- DeleteSkImageAndPreventCaching(context_,
- std::move(pre_converted_image));
- }
+ uploaded_image = MakeTextureImage(
+ context_, std::move(uploaded_image), target_color_space,
+ image_data->needs_mips ? GrMipMapped::kYes : GrMipMapped::kNo);
}
// At-raster may have decoded this while we were unlocked. If so, ignore our
// result.
- if (!image_data->upload.image()) {
- // Take ownership of any GL texture backing for the SkImage. This allows
- // us to use the image with the discardable system.
- if (uploaded_image) {
- uploaded_image = TakeOwnershipOfSkImageBacking(context_->GrContext(),
- std::move(uploaded_image));
- }
+ if (image_data->upload.image()) {
+ if (uploaded_image)
+ DeleteSkImageAndPreventCaching(context_, std::move(uploaded_image));
+ return;
+ }
- // TODO(crbug.com/740737): uploaded_image is sometimes null in certain
- // context-lost situations.
- if (!uploaded_image)
- return;
+ // Take ownership of any GL texture backing for the SkImage. This allows
+ // us to use the image with the discardable system.
+ if (uploaded_image) {
+ uploaded_image = TakeOwnershipOfSkImageBacking(context_->GrContext(),
+ std::move(uploaded_image));
+ }
- image_data->upload.SetImage(std::move(uploaded_image));
+ // TODO(crbug.com/740737): uploaded_image is sometimes null in certain
+ // context-lost situations.
+ if (!uploaded_image)
+ return;
- // If we have a new GPU-backed image, initialize it for use in the GPU
- // discardable system.
- if (image_data->mode == DecodedDataMode::kGpu) {
- // Notify the discardable system of this image so it will count against
- // budgets.
- context_->ContextGL()->InitializeDiscardableTextureCHROMIUM(
- image_data->upload.gl_id());
- }
+ image_data->upload.SetImage(std::move(uploaded_image));
+
+ // If we have a new GPU-backed image, initialize it for use in the GPU
+ // discardable system.
+ if (image_data->mode == DecodedDataMode::kGpu) {
+ // Notify the discardable system of this image so it will count against
+ // budgets.
+ context_->ContextGL()->InitializeDiscardableTextureCHROMIUM(
+ image_data->upload.gl_id());
}
}
@@ -1490,9 +1614,10 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) {
"GpuImageDecodeCache::CreateImageData");
lock_.AssertAcquired();
- WillAddCacheEntry(draw_image);
- int mip_level = CalculateUploadScaleMipLevel(draw_image);
- SkImageInfo image_info = CreateImageInfoForDrawImage(draw_image, mip_level);
+ int upload_scale_mip_level = CalculateUploadScaleMipLevel(draw_image);
+ bool needs_mips = ShouldGenerateMips(draw_image, upload_scale_mip_level);
+ SkImageInfo image_info =
+ CreateImageInfoForDrawImage(draw_image, upload_scale_mip_level);
DecodedDataMode mode;
if (use_transfer_cache_) {
@@ -1522,20 +1647,23 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) {
// However, if the image will be scaled or color converts on the cpu, we
// consider it a lazy image and cache the scaled result in discardable memory.
const bool is_bitmap_backed = !draw_image.paint_image().IsLazyGenerated() &&
- mip_level == 0 &&
+ upload_scale_mip_level == 0 &&
!cache_color_conversion_on_cpu;
- return base::WrapRefCounted(new ImageData(
- mode, data_size, draw_image.target_color_space(),
- CalculateDesiredFilterQuality(draw_image), mip_level, is_bitmap_backed));
+ return base::WrapRefCounted(
+ new ImageData(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));
}
void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) {
- lock_.AssertAcquired();
-
// Remove any old entries for this image. We keep at-most 2 ContentIds for a
// PaintImage (pending and active tree).
- auto& cached_content_ids =
- paint_image_entries_[draw_image.paint_image().stable_id()].content_ids;
+ auto& cache_entries =
+ paint_image_entries_[draw_image.paint_image().stable_id()];
+ cache_entries.count++;
+
+ auto& cached_content_ids = cache_entries.content_ids;
const PaintImage::ContentId new_content_id =
draw_image.frame_key().content_id();
@@ -1568,6 +1696,12 @@ void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) {
}
}
+ // Removing entries from the persistent cache should not erase the tracking
+ // for the current paint_image, since we have 2 different content ids for it
+ // and only one of them was erased above.
+ DCHECK_NE(paint_image_entries_.count(draw_image.paint_image().stable_id()),
+ 0u);
+
cached_content_ids[0] = content_id_to_keep;
cached_content_ids[1] = new_content_id;
}
@@ -1592,6 +1726,12 @@ void GpuImageDecodeCache::UnlockImage(ImageData* image_data) {
ids_pending_unlock_.push_back(*image_data->upload.transfer_cache_id());
}
image_data->upload.OnUnlock();
+
+ // If we were holding onto an unmipped image for defering deletion, do it now
+ // it is guarenteed to have no-refs.
+ auto unmipped_image = image_data->upload.take_unmipped_image();
+ if (unmipped_image)
+ images_pending_deletion_.push_back(std::move(unmipped_image));
}
// We always run pending operations in the following order:
@@ -1703,14 +1843,14 @@ bool GpuImageDecodeCache::TryLockImage(HaveContextLock have_context_lock,
// |draw_image|. First looks for an exact entry in our |in_use_cache_|. If one
// cannot be found, it looks for a compatible entry in our |persistent_cache_|.
GpuImageDecodeCache::ImageData* GpuImageDecodeCache::GetImageDataForDrawImage(
- const DrawImage& draw_image) {
+ const DrawImage& draw_image,
+ const InUseCacheKey& key) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::GetImageDataForDrawImage");
lock_.AssertAcquired();
- DCHECK(!draw_image.paint_image().GetSkImage()->isTextureBacked());
+ DCHECK(UseCacheForDrawImage(draw_image));
- auto found_in_use =
- in_use_cache_.find(InUseCacheKey::FromDrawImage(draw_image));
+ auto found_in_use = in_use_cache_.find(key);
if (found_in_use != in_use_cache_.end())
return found_in_use->second.image_data.get();
@@ -1720,12 +1860,7 @@ GpuImageDecodeCache::ImageData* GpuImageDecodeCache::GetImageDataForDrawImage(
if (IsCompatible(image_data, draw_image)) {
return image_data;
} else {
- found_persistent->second->is_orphaned = true;
- // Call OwnershipChanged before erasing the orphaned task from the
- // persistent cache. This ensures that if the orphaned task has 0
- // references, it is cleaned up safely before it is deleted.
- OwnershipChanged(draw_image, image_data);
- persistent_cache_.Erase(found_persistent);
+ RemoveFromPersistentCache(found_persistent);
}
}
@@ -1738,9 +1873,9 @@ GpuImageDecodeCache::ImageData* GpuImageDecodeCache::GetImageDataForDrawImage(
// the provided |draw_image|.
bool GpuImageDecodeCache::IsCompatible(const ImageData* image_data,
const DrawImage& draw_image) const {
- bool is_scaled = image_data->mip_level != 0;
- bool scale_is_compatible =
- CalculateUploadScaleMipLevel(draw_image) >= image_data->mip_level;
+ bool is_scaled = image_data->upload_scale_mip_level != 0;
+ bool scale_is_compatible = CalculateUploadScaleMipLevel(draw_image) >=
+ image_data->upload_scale_mip_level;
bool quality_is_compatible =
CalculateDesiredFilterQuality(draw_image) <= image_data->quality;
bool color_is_compatible =
@@ -1809,6 +1944,18 @@ void GpuImageDecodeCache::OnPurgeMemory() {
EnsureCapacity(0);
}
+void GpuImageDecodeCache::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level) {
+ switch (level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ OnPurgeMemory();
+ break;
+ }
+}
+
bool GpuImageDecodeCache::SupportsColorSpaceConversion() const {
switch (color_type_) {
case kRGBA_8888_SkColorType:
@@ -1840,4 +1987,61 @@ void GpuImageDecodeCache::CheckContextLockAcquiredIfNecessary() {
context_->GetLock()->AssertAcquired();
}
+void GpuImageDecodeCache::UpdateMipsIfNeeded(const DrawImage& draw_image,
+ ImageData* image_data) {
+ CheckContextLockAcquiredIfNecessary();
+
+ // If we already have mips, nothing to do.
+ if (image_data->needs_mips)
+ return;
+
+ bool needs_mips =
+ ShouldGenerateMips(draw_image, image_data->upload_scale_mip_level);
+ if (!needs_mips)
+ return;
+
+ image_data->needs_mips = true;
+
+ // If we have no uploaded image, nothing to do other than update needs_mips.
+ // Mips will be generated during later upload.
+ if (!image_data->HasUploadedData() ||
+ image_data->mode != DecodedDataMode::kGpu)
+ return;
+
+ // Need to generate mips. Take a reference on the image we're about to delete,
+ // delaying deletion.
+ sk_sp<SkImage> previous_image = image_data->upload.image();
+
+ // Generate a new image from the previous, adding mips.
+ sk_sp<SkImage> image_with_mips = previous_image->makeTextureImage(
+ context_->GrContext(), nullptr, GrMipMapped::kYes);
+
+ // Handle lost context.
+ if (!image_with_mips)
+ return;
+
+ // No need to do anything if mipping this image results in the same texture.
+ // Deleting it below will result in lifetime issues.
+ if (GlIdFromSkImage(image_with_mips.get()) == image_data->upload.gl_id())
+ return;
+
+ // Skia owns our new image, take ownership.
+ sk_sp<SkImage> image_with_mips_owned = TakeOwnershipOfSkImageBacking(
+ context_->GrContext(), std::move(image_with_mips));
+
+ // Handle lost context
+ if (!image_with_mips_owned)
+ return;
+
+ // The previous image might be in the in-use cache, potentially held
+ // externally. We must defer deleting it until the entry is unlocked.
+ image_data->upload.set_unmipped_image(image_data->upload.image());
+
+ // Set the new image on the cache.
+ image_data->upload.Reset();
+ image_data->upload.SetImage(std::move(image_with_mips_owned));
+ context_->ContextGL()->InitializeDiscardableTextureCHROMIUM(
+ image_data->upload.gl_id());
+}
+
} // namespace cc
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h
index 90374d7ab72..54cffb803b8 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.h
+++ b/chromium/cc/tiles/gpu_image_decode_cache.h
@@ -12,6 +12,7 @@
#include "base/containers/mru_cache.h"
#include "base/memory/discardable_memory.h"
#include "base/memory/memory_coordinator_client.h"
+#include "base/memory/memory_pressure_listener.h"
#include "base/synchronization/lock.h"
#include "base/trace_event/memory_dump_provider.h"
#include "cc/cc_export.h"
@@ -109,6 +110,9 @@ class CC_EXPORT GpuImageDecodeCache
int max_texture_size);
~GpuImageDecodeCache() override;
+ // Returns the GL texture ID backing the given SkImage.
+ static GrGLuint GlIdFromSkImage(const SkImage* image);
+
// ImageDecodeCache overrides.
// Finds the existing uploaded image for the provided DrawImage. Creates an
@@ -126,6 +130,7 @@ class CC_EXPORT GpuImageDecodeCache
bool aggressively_free_resources) override;
void ClearCache() override;
size_t GetMaximumMemoryLimitBytes() const override;
+ bool UseCacheForDrawImage(const DrawImage& image) const override;
// MemoryDumpProvider overrides.
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
@@ -135,6 +140,11 @@ class CC_EXPORT GpuImageDecodeCache
void OnMemoryStateChange(base::MemoryState state) override;
void OnPurgeMemory() override;
+ // TODO(gyuyoung): OnMemoryPressure is deprecated. So this should be removed
+ // when the memory coordinator is enabled by default.
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level);
+
// Called by Decode / Upload tasks.
void DecodeImageInTask(const DrawImage& image, TaskType task_type);
void UploadImageInTask(const DrawImage& image);
@@ -161,6 +171,9 @@ class CC_EXPORT GpuImageDecodeCache
bool IsInInUseCacheForTesting(const DrawImage& image) const;
bool IsInPersistentCacheForTesting(const DrawImage& image) const;
sk_sp<SkImage> GetSWImageDecodeForTesting(const DrawImage& image);
+ size_t paint_image_entries_count_for_testing() const {
+ return paint_image_entries_.size();
+ }
private:
enum class DecodedDataMode { kGpu, kCpu, kTransferCache };
@@ -262,6 +275,14 @@ class CC_EXPORT GpuImageDecodeCache
return transfer_cache_id_;
}
+ void set_unmipped_image(sk_sp<SkImage> image) {
+ unmipped_image_ = std::move(image);
+ }
+ sk_sp<SkImage> take_unmipped_image() {
+ DCHECK(!is_locked_);
+ return std::move(unmipped_image_);
+ }
+
private:
// Used for internal DCHECKs only.
enum class Mode {
@@ -281,25 +302,32 @@ class CC_EXPORT GpuImageDecodeCache
// Used if |mode_| == kTransferCache.
base::Optional<uint32_t> transfer_cache_id_;
+
+ // The original un-mipped image, retained until it can be safely deleted.
+ sk_sp<SkImage> unmipped_image_;
};
struct ImageData : public base::RefCountedThreadSafe<ImageData> {
- ImageData(DecodedDataMode mode,
+ ImageData(PaintImage::Id paint_image_id,
+ DecodedDataMode mode,
size_t size,
const gfx::ColorSpace& target_color_space,
SkFilterQuality quality,
- int mip_level,
+ int upload_scale_mip_level,
+ bool needs_mips,
bool is_bitmap_backed);
bool IsGpuOrTransferCache() const;
bool HasUploadedData() const;
void ValidateBudgeted() const;
+ const PaintImage::Id paint_image_id;
const DecodedDataMode mode;
const size_t size;
gfx::ColorSpace target_color_space;
SkFilterQuality quality;
- int mip_level;
+ int upload_scale_mip_level;
+ bool needs_mips = false;
bool is_bitmap_backed;
bool is_budgeted = false;
@@ -339,7 +367,7 @@ class CC_EXPORT GpuImageDecodeCache
explicit InUseCacheKey(const DrawImage& draw_image);
PaintImage::FrameKey frame_key;
- int mip_level;
+ int upload_scale_mip_level;
SkFilterQuality filter_quality;
gfx::ColorSpace target_color_space;
};
@@ -364,10 +392,13 @@ class CC_EXPORT GpuImageDecodeCache
const TracingInfo& tracing_info,
DecodeTaskType task_type);
- void RefImageDecode(const DrawImage& draw_image);
- void UnrefImageDecode(const DrawImage& draw_image);
- void RefImage(const DrawImage& draw_image);
- void UnrefImageInternal(const DrawImage& draw_image);
+ void RefImageDecode(const DrawImage& draw_image,
+ const InUseCacheKey& cache_key);
+ void UnrefImageDecode(const DrawImage& draw_image,
+ const InUseCacheKey& cache_key);
+ void RefImage(const DrawImage& draw_image, const InUseCacheKey& cache_key);
+ void UnrefImageInternal(const DrawImage& draw_image,
+ const InUseCacheKey& cache_key);
// Called any time the ownership of an object changed. This includes changes
// to ref-count or to orphaned status.
@@ -391,7 +422,8 @@ class CC_EXPORT GpuImageDecodeCache
// Finds the ImageData that should be used for the given DrawImage. Looks
// first in the |in_use_cache_|, and then in the |persistent_cache_|.
- ImageData* GetImageDataForDrawImage(const DrawImage& image);
+ ImageData* GetImageDataForDrawImage(const DrawImage& image,
+ const InUseCacheKey& key);
// Returns true if the given ImageData can be used to draw the specified
// DrawImage.
@@ -434,8 +466,13 @@ class CC_EXPORT GpuImageDecodeCache
using PersistentCache = base::HashingMRUCache<PaintImage::FrameKey,
scoped_refptr<ImageData>,
PaintImage::FrameKeyHash>;
- PersistentCache::iterator RemoveFromPersistentCache(
- PersistentCache::iterator it);
+ void AddToPersistentCache(const DrawImage& draw_image,
+ scoped_refptr<ImageData> data);
+ template <typename Iterator>
+ Iterator RemoveFromPersistentCache(Iterator it);
+
+ // Adds mips to an image if required.
+ void UpdateMipsIfNeeded(const DrawImage& draw_image, ImageData* image_data);
const SkColorType color_type_;
const bool use_transfer_cache_ = false;
@@ -452,6 +489,10 @@ class CC_EXPORT GpuImageDecodeCache
struct CacheEntries {
PaintImage::ContentId content_ids[2] = {PaintImage::kInvalidContentId,
PaintImage::kInvalidContentId};
+
+ // The number of cache entries for a PaintImage. Note that there can be
+ // multiple entries per content_id.
+ size_t count = 0u;
};
// A map of PaintImage::Id to entries for this image in the
// |persistent_cache_|.
@@ -480,6 +521,8 @@ class CC_EXPORT GpuImageDecodeCache
// Records the maximum number of items in the cache over the lifetime of the
// cache. This is updated anytime we are requested to reduce cache usage.
size_t lifetime_max_items_in_cache_ = 0u;
+
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
};
} // namespace cc
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
new file mode 100644
index 00000000000..fc4d9321ab9
--- /dev/null
+++ b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
@@ -0,0 +1,183 @@
+// Copyright 2017 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 <vector>
+
+#include "cc/base/lap_timer.h"
+#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 "gpu/command_buffer/client/raster_interface.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+#include "third_party/skia/include/core/SkSurface.h"
+
+namespace cc {
+namespace {
+
+static const int kTimeLimitMillis = 2000;
+static const int kWarmupRuns = 5;
+static const int kTimeCheckInterval = 10;
+static const int kCacheSize = 128 * 1024 * 1024;
+
+sk_sp<SkImage> CreateImage(int width, int height) {
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeS32(width, height, kPremul_SkAlphaType));
+ return SkImage::MakeFromBitmap(bitmap);
+}
+
+SkMatrix CreateMatrix(const SkSize& scale) {
+ SkMatrix matrix;
+ matrix.setScale(scale.width(), scale.height());
+ return matrix;
+}
+
+enum class TestMode { kGpu, kTransferCache, kSw };
+
+class GpuImageDecodeCachePerfTest
+ : public testing::Test,
+ public testing::WithParamInterface<TestMode> {
+ public:
+ GpuImageDecodeCachePerfTest()
+ : timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval),
+ context_provider_(base::MakeRefCounted<TestInProcessContextProvider>(
+ UseTransferCache(),
+ false /* support_locking */)),
+ cache_(context_provider_.get(),
+ UseTransferCache(),
+ kRGBA_8888_SkColorType,
+ kCacheSize,
+ MaxTextureSize()) {}
+
+ protected:
+ size_t MaxTextureSize() const {
+ switch (GetParam()) {
+ case TestMode::kGpu:
+ case TestMode::kTransferCache:
+ return 4096;
+ case TestMode::kSw:
+ return 0;
+ }
+ }
+
+ bool UseTransferCache() const {
+ return GetParam() == TestMode::kTransferCache;
+ }
+
+ const char* ParamName() const {
+ switch (GetParam()) {
+ case TestMode::kGpu:
+ return "GPU";
+ case TestMode::kTransferCache:
+ return "TransferCache";
+ case TestMode::kSw:
+ return "SW";
+ }
+ }
+
+ LapTimer timer_;
+ scoped_refptr<TestInProcessContextProvider> context_provider_;
+ GpuImageDecodeCache cache_;
+};
+
+INSTANTIATE_TEST_CASE_P(P,
+ GpuImageDecodeCachePerfTest,
+ testing::Values(TestMode::kGpu,
+ TestMode::kTransferCache,
+ TestMode::kSw));
+
+TEST_P(GpuImageDecodeCachePerfTest, DecodeWithColorConversion) {
+ timer_.Reset();
+ do {
+ DrawImage image(
+ PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId())
+ .TakePaintImage(),
+ SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u,
+ gfx::ColorSpace::CreateXYZD50());
+
+ DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
+ cache_.DrawWithImageFinished(image, decoded_image);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("gpu_image_decode_cache_decode_with_color_conversion",
+ ParamName(), "result", timer_.LapsPerSecond(),
+ "runs/s", true);
+}
+
+using GpuImageDecodeCachePerfTestNoSw = GpuImageDecodeCachePerfTest;
+INSTANTIATE_TEST_CASE_P(P,
+ GpuImageDecodeCachePerfTestNoSw,
+ testing::Values(TestMode::kGpu,
+ TestMode::kTransferCache));
+
+TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) {
+ // Surface to render into.
+ auto surface = SkSurface::MakeRenderTarget(
+ context_provider_->GrContext(), SkBudgeted::kNo,
+ SkImageInfo::MakeN32Premul(2048, 2048));
+
+ timer_.Reset();
+ do {
+ DrawImage image(
+ PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId())
+ .TakePaintImage(),
+ SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
+ CreateMatrix(SkSize::Make(0.6f, 0.6f)), 0u, gfx::ColorSpace());
+
+ DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
+
+ if (GetParam() == TestMode::kGpu) {
+ SkPaint paint;
+ paint.setFilterQuality(kMedium_SkFilterQuality);
+ surface->getCanvas()->drawImageRect(decoded_image.image().get(),
+ SkRect::MakeWH(1024, 2048),
+ SkRect::MakeWH(614, 1229), &paint);
+ surface->prepareForExternalIO();
+ }
+
+ cache_.DrawWithImageFinished(image, decoded_image);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("gpu_image_decode_cache_decode_with_mips", ParamName(),
+ "result", timer_.LapsPerSecond(), "runs/s", true);
+}
+
+TEST_P(GpuImageDecodeCachePerfTest, AcquireExistingImages) {
+ timer_.Reset();
+ DrawImage image(
+ PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId())
+ .TakePaintImage(),
+ SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u,
+ gfx::ColorSpace::CreateXYZD50());
+
+ DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
+ cache_.DrawWithImageFinished(image, decoded_image);
+
+ do {
+ DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
+ cache_.DrawWithImageFinished(image, decoded_image);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("gpu_image_decode_cache_acquire_existing_images",
+ ParamName(), "result", timer_.LapsPerSecond(),
+ "runs/s", true);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
index 91fc94f17e2..5c208a7f605 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -15,10 +15,10 @@
#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 "components/viz/test/test_web_graphics_context_3d.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"
namespace cc {
@@ -61,6 +61,16 @@ class FakeDiscardableManager {
cached_textures_limit_ = limit;
}
+ void ExpectLocked(GLuint texture_id) {
+ EXPECT_TRUE(textures_.end() != textures_.find(texture_id));
+
+ // Any value > kHandleLockedStart represents a locked texture. As we
+ // increment this value with each lock, we need the entire range and can't
+ // add additional values > kHandleLockedStart in the future.
+ EXPECT_GE(textures_[texture_id], kHandleLockedStart);
+ EXPECT_LE(textures_[texture_id], kHandleLockedEnd);
+ }
+
private:
void EnforceLimit() {
for (auto it = textures_.begin(); it != textures_.end(); ++it) {
@@ -75,16 +85,6 @@ class FakeDiscardableManager {
}
}
- void ExpectLocked(GLuint texture_id) {
- EXPECT_TRUE(textures_.end() != textures_.find(texture_id));
-
- // Any value > kHandleLockedStart represents a locked texture. As we
- // increment this value with each lock, we need the entire range and can't
- // add additional values > kHandleLockedStart in the future.
- EXPECT_GE(textures_[texture_id], kHandleLockedStart);
- EXPECT_LE(textures_[texture_id], kHandleLockedEnd);
- }
-
const int32_t kHandleDeleted = 0;
const int32_t kHandleUnlocked = 1;
const int32_t kHandleLockedStart = 2;
@@ -102,17 +102,17 @@ class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface,
explicit FakeGPUImageDecodeTestGLES2Interface(
FakeDiscardableManager* discardable_manager,
TransferCacheTestHelper* transfer_cache_helper)
- : extension_string_("GL_EXT_texture_format_BGRA8888 GL_OES_rgb8_rgba8"),
+ : extension_string_(
+ "GL_EXT_texture_format_BGRA8888 GL_OES_rgb8_rgba8 "
+ "GL_OES_texture_npot"),
discardable_manager_(discardable_manager),
transfer_cache_helper_(transfer_cache_helper) {}
~FakeGPUImageDecodeTestGLES2Interface() override {
// All textures / framebuffers / renderbuffers should be cleaned up.
- if (test_context_) {
- EXPECT_EQ(0u, test_context_->NumTextures());
- EXPECT_EQ(0u, test_context_->NumFramebuffers());
- EXPECT_EQ(0u, test_context_->NumRenderbuffers());
- }
+ EXPECT_EQ(0u, NumTextures());
+ EXPECT_EQ(0u, NumFramebuffers());
+ EXPECT_EQ(0u, NumRenderbuffers());
}
void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) override {
@@ -190,6 +190,9 @@ class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface,
case GL_MAX_RENDERBUFFER_SIZE:
*params = 2048;
return;
+ case GL_MAX_VERTEX_ATTRIBS:
+ *params = 8;
+ return;
default:
break;
}
@@ -219,26 +222,33 @@ class GPUImageDecodeTestMockContextProvider : public viz::TestContextProvider {
std::make_unique<FakeGPUImageDecodeTestGLES2Interface>(
discardable_manager, transfer_cache_helper),
std::make_unique<FakeGPUImageDecodeTestGLES2Interface>(
- discardable_manager, transfer_cache_helper),
- viz::TestWebGraphicsContext3D::Create());
+ discardable_manager, transfer_cache_helper));
}
private:
~GPUImageDecodeTestMockContextProvider() override = default;
GPUImageDecodeTestMockContextProvider(
std::unique_ptr<viz::TestContextSupport> support,
- std::unique_ptr<viz::TestGLES2Interface> gl,
- std::unique_ptr<viz::TestWebGraphicsContext3D> context)
- : TestContextProvider(std::move(support),
- std::move(gl),
- std::move(context),
- true) {}
+ std::unique_ptr<viz::TestGLES2Interface> gl)
+ : TestContextProvider(std::move(support), std::move(gl), true) {}
};
gfx::ColorSpace DefaultColorSpace() {
return gfx::ColorSpace::CreateSRGB();
}
+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;
+}
+
size_t kGpuMemoryLimitBytes = 96 * 1024 * 1024;
class GpuImageDecodeCacheTest
@@ -248,7 +258,8 @@ class GpuImageDecodeCacheTest
void SetUp() override {
context_provider_ = GPUImageDecodeTestMockContextProvider::Create(
&discardable_manager_, &transfer_cache_helper_);
- discardable_manager_.SetGLES2Interface(context_provider_->TestContextGL());
+ discardable_manager_.SetGLES2Interface(
+ context_provider_->UnboundTestContextGL());
context_provider_->BindToCurrentThread();
{
viz::RasterContextProvider::ScopedRasterContextLock context_lock(
@@ -288,12 +299,13 @@ class GpuImageDecodeCacheTest
DecodedDrawImage EnsureImageBacked(DecodedDrawImage&& draw_image) {
if (draw_image.transfer_cache_entry_id()) {
EXPECT_TRUE(use_transfer_cache_);
- sk_sp<SkImage> image = transfer_cache_helper_
- .GetEntryAs<ServiceImageTransferCacheEntry>(
- *draw_image.transfer_cache_entry_id())
- ->image();
+ auto* image_entry =
+ transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>(
+ *draw_image.transfer_cache_entry_id());
+ if (draw_image.transfer_cache_entry_needs_mips())
+ image_entry->EnsureMips();
DecodedDrawImage new_draw_image(
- std::move(image), draw_image.src_rect_offset(),
+ image_entry->image(), draw_image.src_rect_offset(),
draw_image.scale_adjustment(), draw_image.filter_quality(),
draw_image.is_budgeted());
return new_draw_image;
@@ -321,18 +333,6 @@ class GpuImageDecodeCacheTest
int max_texture_size_ = 0;
};
-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;
-}
-
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
auto cache = CreateCache();
PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
@@ -2392,6 +2392,317 @@ TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) {
for (int i = 0; i < 10; ++i) {
cache->DrawWithImageFinished(draw_images[i], decoded_draw_images[i]);
}
+
+ // We have a single tracked entry, that gets cleared once we purge the cache.
+ EXPECT_EQ(cache->paint_image_entries_count_for_testing(), 1u);
+ cache->OnPurgeMemory();
+ EXPECT_EQ(cache->paint_image_entries_count_for_testing(), 0u);
+}
+
+TEST_P(GpuImageDecodeCacheTest, DecodeToScale) {
+ auto cache = CreateCache();
+ bool is_decomposable = true;
+ SkFilterQuality quality = kMedium_SkFilterQuality;
+
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ SkISize full_size = SkISize::Make(100, 100);
+ std::vector<SkISize> supported_sizes = {SkISize::Make(25, 25),
+ SkISize::Make(50, 50)};
+ std::vector<FrameMetadata> frames = {FrameMetadata()};
+ sk_sp<FakePaintImageGenerator> generator =
+ sk_make_sp<FakePaintImageGenerator>(
+ SkImageInfo::MakeN32Premul(full_size.width(), full_size.height(),
+ DefaultColorSpace().ToSkColorSpace()),
+ frames, true, supported_sizes);
+ PaintImage paint_image = PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_frame_index(0u)
+ .TakePaintImage();
+
+ DrawImage draw_image1(
+ paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
+ quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
+ PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DecodedDrawImage decoded_image1 =
+ EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image1));
+ ASSERT_TRUE(decoded_image1.image());
+ EXPECT_EQ(decoded_image1.image()->width(), 50);
+ EXPECT_EQ(decoded_image1.image()->height(), 50);
+
+ // We should have requested a scaled decode from the generator.
+ ASSERT_EQ(generator->decode_infos().size(), 1u);
+ EXPECT_EQ(generator->decode_infos().at(0).width(), 50);
+ EXPECT_EQ(generator->decode_infos().at(0).height(), 50);
+ cache->DrawWithImageFinished(draw_image1, decoded_image1);
+}
+
+TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) {
+ 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);
+ std::vector<SkISize> supported_sizes = {SkISize::Make(25, 25),
+ SkISize::Make(50, 50)};
+ std::vector<FrameMetadata> frames = {FrameMetadata()};
+ sk_sp<FakePaintImageGenerator> generator =
+ sk_make_sp<FakePaintImageGenerator>(
+ SkImageInfo::MakeN32Premul(full_size.width(), full_size.height(),
+ DefaultColorSpace().ToSkColorSpace()),
+ frames, true, supported_sizes);
+ PaintImage paint_image = PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_frame_index(0u)
+ .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());
+ DecodedDrawImage decoded_image =
+ EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ ASSERT_TRUE(decoded_image.image());
+ EXPECT_EQ(decoded_image.image()->width(), 50);
+ EXPECT_EQ(decoded_image.image()->height(), 50);
+
+ // We should have requested the original decode from the generator.
+ ASSERT_EQ(generator->decode_infos().size(), 1u);
+ EXPECT_EQ(generator->decode_infos().at(0).width(), 100);
+ EXPECT_EQ(generator->decode_infos().at(0).height(), 100);
+ cache->DrawWithImageFinished(draw_image, decoded_image);
+}
+
+TEST_P(GpuImageDecodeCacheTest, BasicMips) {
+ auto decode_and_check_mips = [this](SkFilterQuality filter_quality,
+ SkSize scale, gfx::ColorSpace color_space,
+ bool should_have_mips) {
+ auto cache = CreateCache();
+ bool is_decomposable = true;
+
+ PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ filter_quality, CreateMatrix(scale, is_decomposable),
+ PaintImage::kDefaultFrameIndex, color_space);
+ 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());
+ DecodedDrawImage decoded_draw_image =
+ EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+
+ sk_sp<SkImage> image_with_mips =
+ decoded_draw_image.image()->makeTextureImage(
+ context_provider()->GrContext(), nullptr, GrMipMapped::kYes);
+ EXPECT_EQ(should_have_mips, image_with_mips == decoded_draw_image.image());
+
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+ };
+
+ // No scale == no mips.
+ decode_and_check_mips(kMedium_SkFilterQuality, SkSize::Make(1.0f, 1.0f),
+ DefaultColorSpace(), false);
+ // Full mip level scale == no mips
+ decode_and_check_mips(kMedium_SkFilterQuality, SkSize::Make(0.5f, 0.5f),
+ DefaultColorSpace(), false);
+ // Low filter quality == no mips
+ decode_and_check_mips(kLow_SkFilterQuality, SkSize::Make(0.6f, 0.6f),
+ DefaultColorSpace(), false);
+ // None filter quality == no mips
+ decode_and_check_mips(kNone_SkFilterQuality, SkSize::Make(0.6f, 0.6f),
+ DefaultColorSpace(), false);
+ // 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);
+}
+
+TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
+ auto cache = CreateCache();
+ bool is_decomposable = true;
+ auto filter_quality = kMedium_SkFilterQuality;
+
+ PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
+
+ // 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());
+ 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());
+ DecodedDrawImage decoded_draw_image =
+ EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+
+ // No mips should be generated
+ sk_sp<SkImage> image_with_mips =
+ decoded_draw_image.image()->makeTextureImage(
+ context_provider()->GrContext(), nullptr, GrMipMapped::kYes);
+ EXPECT_NE(image_with_mips, decoded_draw_image.image());
+
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+ }
+
+ // Call ReduceCacheUsage to clean up.
+ cache->ReduceCacheUsage();
+
+ // Request the same image again, but this time with a scale. We should get
+ // 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());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ EXPECT_FALSE(result.task);
+
+ // Must hold context lock before calling GetDecodedImageForDraw /
+ // DrawWithImageFinished.
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ DecodedDrawImage decoded_draw_image =
+ EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+
+ EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+
+ // Mips should be generated
+ sk_sp<SkImage> image_with_mips =
+ decoded_draw_image.image()->makeTextureImage(
+ context_provider()->GrContext(), nullptr, GrMipMapped::kYes);
+ EXPECT_EQ(image_with_mips, decoded_draw_image.image());
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+ }
+}
+
+TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
+#if defined(OS_WIN)
+ // TODO(ericrk): Mips are temporarily disabled to investigate a memory
+ // regression on Windows. https://crbug.com/867468
+ return;
+#endif // defined(OS_WIN)
+
+ auto cache = CreateCache();
+ bool is_decomposable = true;
+ auto filter_quality = kMedium_SkFilterQuality;
+
+ PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
+
+ struct Decode {
+ DrawImage image;
+ DecodedDrawImage decoded_image;
+ };
+ std::vector<Decode> images_to_unlock;
+
+ // 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());
+ 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());
+ DecodedDrawImage decoded_draw_image =
+ EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+
+ // No mips should be generated
+ sk_sp<SkImage> image_with_mips =
+ decoded_draw_image.image()->makeTextureImage(
+ context_provider()->GrContext(), nullptr, GrMipMapped::kYes);
+ EXPECT_NE(image_with_mips, decoded_draw_image.image());
+
+ images_to_unlock.push_back({draw_image, decoded_draw_image});
+ }
+
+ // 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());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ EXPECT_FALSE(result.task);
+
+ // Must hold context lock before calling GetDecodedImageForDraw /
+ // DrawWithImageFinished.
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ DecodedDrawImage decoded_draw_image =
+ EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+
+ EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+
+ // Mips should be generated
+ sk_sp<SkImage> image_with_mips =
+ decoded_draw_image.image()->makeTextureImage(
+ context_provider()->GrContext(), nullptr, GrMipMapped::kYes);
+ EXPECT_EQ(image_with_mips, decoded_draw_image.image());
+
+ images_to_unlock.push_back({draw_image, decoded_draw_image});
+ }
+
+ // Reduce cache usage to make sure anything marked for deletion is actually
+ // deleted.
+ cache->ReduceCacheUsage();
+
+ {
+ // All images which are currently ref-ed must have locked textures.
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ for (const auto& decode : images_to_unlock) {
+ if (!use_transfer_cache_) {
+ discardable_manager_.ExpectLocked(GpuImageDecodeCache::GlIdFromSkImage(
+ decode.decoded_image.image().get()));
+ }
+ cache->DrawWithImageFinished(decode.image, decode.decoded_image);
+ cache->UnrefImage(decode.image);
+ }
+ }
}
INSTANTIATE_TEST_CASE_P(
diff --git a/chromium/cc/tiles/image_decode_cache.h b/chromium/cc/tiles/image_decode_cache.h
index a1653f4708d..7c75dd9d7c5 100644
--- a/chromium/cc/tiles/image_decode_cache.h
+++ b/chromium/cc/tiles/image_decode_cache.h
@@ -138,6 +138,11 @@ class CC_EXPORT ImageDecodeCache {
// locked budget before creating a task.
virtual size_t GetMaximumMemoryLimitBytes() const = 0;
+ // Returns true if the cache should be used for |image|. In certain cases the
+ // 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);
};
diff --git a/chromium/cc/tiles/mipmap_util.cc b/chromium/cc/tiles/mipmap_util.cc
index e20f9f0405a..8d018f6280a 100644
--- a/chromium/cc/tiles/mipmap_util.cc
+++ b/chromium/cc/tiles/mipmap_util.cc
@@ -4,13 +4,25 @@
#include "cc/tiles/mipmap_util.h"
+#include "base/numerics/safe_math.h"
+
namespace cc {
namespace {
-// Calculates the size of |axis_base_size| at the given |mip_level| using
-// OpenGL rounding rules.
+// Calculates the size of |axis_base_size| at the given |mip_level|. Note that
+// the calculation here rounds up for consistency with size calculations in the
+// JPEG decoder. This allows us to decode images to the mip size directly.
int ScaleAxisToMipLevel(int axis_base_size, int mip_level) {
DCHECK_GE(mip_level, 0);
DCHECK_LT(mip_level, 32);
+
+ if (mip_level == 0)
+ return axis_base_size;
+
+ // Increment the size by (2^mip_level - 1) so we round on when dividing it
+ // below.
+ base::CheckedNumeric<int> base_size = axis_base_size;
+ base_size += (1 << mip_level) - 1;
+ axis_base_size = base_size.ValueOrDefault(std::numeric_limits<int>::max());
return std::max(1, axis_base_size >> mip_level);
}
diff --git a/chromium/cc/tiles/mipmap_util_unittest.cc b/chromium/cc/tiles/mipmap_util_unittest.cc
index ff1819c82f3..edbe87b5bed 100644
--- a/chromium/cc/tiles/mipmap_util_unittest.cc
+++ b/chromium/cc/tiles/mipmap_util_unittest.cc
@@ -85,8 +85,8 @@ TEST(MipMapUtilTest, NonSquare) {
// Ensures that we handle rounding images correctly.
TEST(MipMapUtilTest, Rounding) {
const gfx::Size src_size(49, 49);
- const gfx::Size target_size_larger(25, 25);
- const gfx::Size target_size_smaller(24, 24);
+ const gfx::Size target_size_larger(26, 26);
+ const gfx::Size target_size_smaller(25, 25);
const int target_level_larger = 0;
const int target_level_smaller = 1;
const SkSize expected_scale_larger = SkSize::Make(1, 1);
@@ -116,5 +116,15 @@ TEST(MipMapUtilTest, Rounding) {
MipMapUtil::GetScaleAdjustmentForSize(src_size, target_size_smaller));
}
+// Ensures that we round up during mip calculation.
+TEST(MipMapUtilTest, RoundUp) {
+ const gfx::Size src_sizes[] = {gfx::Size(3, 3), gfx::Size(5, 7),
+ gfx::Size(11, 14), gfx::Size(17, 31)};
+ for (int i = 0; i < 4; ++i) {
+ EXPECT_EQ(MipMapUtil::GetSizeForLevel(src_sizes[i], i + 1),
+ gfx::Size(2, 2));
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
index c1f7703c5f3..b18a67c20a2 100644
--- a/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
+++ b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
@@ -7,12 +7,11 @@
#include <map>
#include <vector>
-#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_picture_layer_tiling_client.h"
#include "cc/test/fake_raster_source.h"
-#include "cc/test/fake_resource_provider.h"
#include "cc/trees/layer_tree_settings.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/test/fake_output_surface.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -246,9 +245,8 @@ class PictureLayerTilingSetTestWithResources : public testing::Test {
viz::TestContextProvider::Create();
ASSERT_EQ(context_provider->BindToCurrentThread(),
gpu::ContextResult::kSuccess);
- std::unique_ptr<LayerTreeResourceProvider> resource_provider =
- FakeResourceProvider::CreateLayerTreeResourceProvider(
- context_provider.get());
+ std::unique_ptr<viz::ClientResourceProvider> resource_provider =
+ std::make_unique<viz::ClientResourceProvider>(true);
FakePictureLayerTilingClient client(resource_provider.get(),
context_provider.get());
diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc
index 6a52e91c066..05038746066 100644
--- a/chromium/cc/tiles/software_image_decode_cache.cc
+++ b/chromium/cc/tiles/software_image_decode_cache.cc
@@ -24,23 +24,6 @@ using base::trace_event::MemoryDumpLevelOfDetail;
namespace cc {
namespace {
-bool UseCacheForDrawImage(const DrawImage& draw_image) {
- // Lazy generated images are have their decode cached.
- sk_sp<SkImage> sk_image = draw_image.paint_image().GetSkImage();
- if (sk_image->isLazyGenerated())
- return true;
-
- // Cache images that need to be converted to a non-sRGB color space.
- // TODO(ccameron): Consider caching when any color conversion is required.
- // https://crbug.com/791828
- const gfx::ColorSpace& dst_color_space = draw_image.target_color_space();
- if (dst_color_space.IsValid() &&
- dst_color_space != gfx::ColorSpace::CreateSRGB()) {
- return true;
- }
-
- return false;
-}
// The number of entries to keep around in the cache. This limit can be breached
// if more items are locked. That is, locked items ignore this limit.
@@ -172,6 +155,9 @@ SoftwareImageDecodeCache::SoftwareImageDecodeCache(
}
// Register this component with base::MemoryCoordinatorClientRegistry.
base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
+ memory_pressure_listener_.reset(new base::MemoryPressureListener(
+ base::BindRepeating(&SoftwareImageDecodeCache::OnMemoryPressure,
+ base::Unretained(this))));
}
SoftwareImageDecodeCache::~SoftwareImageDecodeCache() {
@@ -383,43 +369,37 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary(
base::AutoUnlock release(lock_);
local_cache_entry = Utils::DoDecodeImage(key, paint_image, color_type_);
} else {
- // Use the full image decode to generate a scaled/subrected decode.
- // TODO(vmpstr): This part needs to handle decode to scale.
- base::Optional<CacheKey> candidate_key;
- auto image_keys_it = frame_key_to_image_keys_.find(key.frame_key());
- // We know that we must have at least our own |entry| in this list, so it
- // won't be empty.
- DCHECK(image_keys_it != frame_key_to_image_keys_.end());
-
- auto& available_keys = image_keys_it->second;
- std::sort(available_keys.begin(), available_keys.end(),
- [](const CacheKey& one, const CacheKey& two) {
- // Return true if |one| scale is less than |two| scale.
- return one.target_size().width() < two.target_size().width() &&
- one.target_size().height() < two.target_size().height();
- });
-
- for (auto& available_key : available_keys) {
- // Only consider keys coming from the same src rect, since otherwise the
- // resulting image was extracted using a different src.
- if (available_key.src_rect() != key.src_rect())
- continue;
-
- // that are at least as big as the required |key|.
- if (available_key.target_size().width() < key.target_size().width() ||
- available_key.target_size().height() < key.target_size().height()) {
- continue;
- }
- auto image_it = decoded_images_.Peek(available_key);
- DCHECK(image_it != decoded_images_.end());
- auto* available_entry = image_it->second.get();
- if (available_entry->is_locked || available_entry->Lock()) {
- candidate_key.emplace(available_key);
- break;
- }
+ // Attempt to find a cached decode to generate a scaled/subrected decode
+ // from.
+ base::Optional<CacheKey> candidate_key = FindCachedCandidate(key);
+
+ SkISize desired_size = gfx::SizeToSkISize(key.target_size());
+ const bool should_decode_to_scale =
+ // Prefer scaling from a cached decode instead of performing another
+ // decode to the desired size.
+ !candidate_key &&
+ // We need the original decode to subrect before scaling, if a subrect
+ // is requested.
+ key.src_rect() ==
+ gfx::Rect(paint_image.width(), paint_image.height()) &&
+ // Note that in the case where we can't decode to the exact desired
+ // size, but a size lower than the original, it would be better to
+ // decode to that size and then scale to the desired size. But this
+ // should be rare in practice, since we only decode to mip levels.
+ paint_image.GetSupportedDecodeSize(desired_size) == desired_size;
+
+ // We don't scale and cache the result if nearest neighbor is requested,
+ // i.e., the processing type should be kOriginal or kSubrectOriginal. And
+ // requesting a subrect already vetoes decode to scale.
+ DCHECK(!should_decode_to_scale || !key.is_nearest_neighbor());
+ if (should_decode_to_scale) {
+ base::AutoUnlock release(lock_);
+ local_cache_entry = Utils::DoDecodeImage(key, paint_image, color_type_);
}
- if (!candidate_key) {
+ // Couldn't decode to scale or find a cached candidate. Create the
+ // intermediate candidate key required for this decode.
+ if (!should_decode_to_scale && !candidate_key) {
// IMPORTANT: There is a bit of a subtlety here. We would normally want to
// generate a new candidate with the key.src_rect() as the src_rect. This
// would ensure that when scaling we won't need to peek pixels, since it's
@@ -445,25 +425,27 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary(
candidate_key.emplace(
CacheKey::FromDrawImage(candidate_draw_image, color_type_));
}
- CHECK(*candidate_key != key) << key.ToString();
- auto decoded_draw_image =
- GetDecodedImageForDrawInternal(*candidate_key, paint_image);
- if (!decoded_draw_image.image()) {
- local_cache_entry = nullptr;
- } else {
- base::AutoUnlock release(lock_);
- // IMPORTANT: More subtleties:
- // If the candidate could have used the original decode, that means we
- // need to extractSubset from it. In all other cases, this would have
- // already been done to generate the candidate.
- local_cache_entry = Utils::GenerateCacheEntryFromCandidate(
- key, decoded_draw_image, candidate_key->type() == CacheKey::kOriginal,
- color_type_);
- }
+ if (candidate_key) {
+ CHECK(*candidate_key != key) << key.ToString();
+ auto decoded_draw_image =
+ GetDecodedImageForDrawInternal(*candidate_key, paint_image);
+ if (!decoded_draw_image.image()) {
+ local_cache_entry = nullptr;
+ } else {
+ base::AutoUnlock release(lock_);
+ // IMPORTANT: More subtleties:
+ // If the candidate could have used the original decode, that means we
+ // need to extractSubset from it. In all other cases, this would have
+ // already been done to generate the candidate.
+ local_cache_entry = Utils::GenerateCacheEntryFromCandidate(
+ key, decoded_draw_image,
+ candidate_key->type() == CacheKey::kOriginal, color_type_);
+ }
- // Unref to balance the GetDecodedImageForDrawInternal() call.
- UnrefImage(*candidate_key);
+ // Unref to balance the GetDecodedImageForDrawInternal() call.
+ UnrefImage(*candidate_key);
+ }
}
if (!local_cache_entry) {
@@ -488,15 +470,70 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary(
}
}
+base::Optional<SoftwareImageDecodeCache::CacheKey>
+SoftwareImageDecodeCache::FindCachedCandidate(const CacheKey& key) {
+ auto image_keys_it = frame_key_to_image_keys_.find(key.frame_key());
+ // We know that we must have at least our own |entry| in this list, so it
+ // won't be empty.
+ DCHECK(image_keys_it != frame_key_to_image_keys_.end());
+
+ auto& available_keys = image_keys_it->second;
+ std::sort(available_keys.begin(), available_keys.end(),
+ [](const CacheKey& one, const CacheKey& two) {
+ // Return true if |one| scale is less than |two| scale.
+ return one.target_size().width() < two.target_size().width() &&
+ one.target_size().height() < two.target_size().height();
+ });
+
+ for (auto& available_key : available_keys) {
+ // Only consider keys coming from the same src rect, since otherwise the
+ // resulting image was extracted using a different src.
+ if (available_key.src_rect() != key.src_rect())
+ continue;
+
+ // That are at least as big as the required |key|.
+ if (available_key.target_size().width() < key.target_size().width() ||
+ available_key.target_size().height() < key.target_size().height()) {
+ continue;
+ }
+ auto image_it = decoded_images_.Peek(available_key);
+ DCHECK(image_it != decoded_images_.end());
+ auto* available_entry = image_it->second.get();
+ if (available_entry->is_locked || available_entry->Lock()) {
+ return available_key;
+ }
+ }
+
+ return base::nullopt;
+}
+
+bool SoftwareImageDecodeCache::UseCacheForDrawImage(
+ const DrawImage& draw_image) const {
+ sk_sp<SkImage> sk_image = draw_image.paint_image().GetSkImage();
+
+ // Software cache doesn't support using texture backed images.
+ if (sk_image->isTextureBacked())
+ return false;
+
+ // Lazy generated images need to have their decode cached.
+ if (sk_image->isLazyGenerated())
+ return true;
+
+ // Cache images that need to be converted to a non-sRGB color space.
+ // TODO(ccameron): Consider caching when any color conversion is required.
+ // https://crbug.com/791828
+ const gfx::ColorSpace& dst_color_space = draw_image.target_color_space();
+ if (dst_color_space.IsValid() &&
+ dst_color_space != gfx::ColorSpace::CreateSRGB()) {
+ return true;
+ }
+
+ return false;
+}
+
DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDraw(
const DrawImage& draw_image) {
- // Non-cached images are be used for raster directly.
- if (!UseCacheForDrawImage(draw_image)) {
- return DecodedDrawImage(draw_image.paint_image().GetSkImage(),
- SkSize::Make(0, 0), SkSize::Make(1.f, 1.f),
- draw_image.filter_quality(),
- true /* is_budgeted */);
- }
+ DCHECK(UseCacheForDrawImage(draw_image));
base::AutoLock hold(lock_);
return GetDecodedImageForDrawInternal(
@@ -538,9 +575,7 @@ DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDrawInternal(
void SoftwareImageDecodeCache::DrawWithImageFinished(
const DrawImage& image,
const DecodedDrawImage& decoded_image) {
- if (!UseCacheForDrawImage(image))
- return;
-
+ DCHECK(UseCacheForDrawImage(image));
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"SoftwareImageDecodeCache::DrawWithImageFinished", "key",
CacheKey::FromDrawImage(image, color_type_).ToString());
@@ -670,6 +705,19 @@ void SoftwareImageDecodeCache::OnPurgeMemory() {
ReduceCacheUsageUntilWithinLimit(0);
}
+void SoftwareImageDecodeCache::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level) {
+ base::AutoLock lock(lock_);
+ switch (level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ ReduceCacheUsageUntilWithinLimit(0);
+ break;
+ }
+}
+
SoftwareImageDecodeCache::CacheEntry* SoftwareImageDecodeCache::AddCacheEntry(
const CacheKey& key) {
lock_.AssertAcquired();
diff --git a/chromium/cc/tiles/software_image_decode_cache.h b/chromium/cc/tiles/software_image_decode_cache.h
index 0fa379c2b2f..e3e6b74f24f 100644
--- a/chromium/cc/tiles/software_image_decode_cache.h
+++ b/chromium/cc/tiles/software_image_decode_cache.h
@@ -12,6 +12,7 @@
#include "base/containers/mru_cache.h"
#include "base/memory/memory_coordinator_client.h"
+#include "base/memory/memory_pressure_listener.h"
#include "base/memory/ref_counted.h"
#include "base/numerics/safe_math.h"
#include "base/trace_event/memory_dump_provider.h"
@@ -52,6 +53,7 @@ class CC_EXPORT SoftwareImageDecodeCache
bool aggressively_free_resources) override {}
void ClearCache() override;
size_t GetMaximumMemoryLimitBytes() const override;
+ bool UseCacheForDrawImage(const DrawImage& image) const override;
// Decode the given image and store it in the cache. This is only called by an
// image decode task from a worker thread.
@@ -115,6 +117,11 @@ class CC_EXPORT SoftwareImageDecodeCache
void OnMemoryStateChange(base::MemoryState state) override;
void OnPurgeMemory() override;
+ // TODO(gyuyoung): OnMemoryPressure is deprecated. So this should be removed
+ // when the memory coordinator is enabled by default.
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level);
+
// Helper method to get the different tasks. Note that this should be used as
// if it was public (ie, all of the locks need to be properly acquired).
TaskResult GetTaskForImageAndRefInternal(const DrawImage& image,
@@ -128,6 +135,7 @@ class CC_EXPORT SoftwareImageDecodeCache
CacheEntry* cache_entry);
void AddBudgetForImage(const CacheKey& key, CacheEntry* entry);
void RemoveBudgetForImage(const CacheKey& key, CacheEntry* entry);
+ base::Optional<CacheKey> FindCachedCandidate(const CacheKey& key);
void UnrefImage(const CacheKey& key);
@@ -140,6 +148,8 @@ class CC_EXPORT SoftwareImageDecodeCache
// Decoded images and ref counts (predecode path).
ImageMRUCache decoded_images_;
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
// A map of PaintImage::FrameKey to the ImageKeys for cached decodes of this
// PaintImage.
std::unordered_map<PaintImage::FrameKey,
diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest.cc b/chromium/cc/tiles/software_image_decode_cache_unittest.cc
index c9f8c5a55e0..9c0c143d167 100644
--- a/chromium/cc/tiles/software_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_unittest.cc
@@ -396,9 +396,9 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_1Scale) {
draw_image, kN32_SkColorType);
EXPECT_EQ(draw_image.frame_key(), key.frame_key());
EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale);
- EXPECT_EQ(62, key.target_size().width());
+ EXPECT_EQ(63, key.target_size().width());
EXPECT_EQ(25, key.target_size().height());
- EXPECT_EQ(62u * 25u * 4u, key.locked_bytes());
+ EXPECT_EQ(63u * 25u * 4u, key.locked_bytes());
}
TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_01Scale) {
@@ -415,9 +415,9 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_01Scale) {
draw_image, kN32_SkColorType);
EXPECT_EQ(draw_image.frame_key(), key.frame_key());
EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale);
- EXPECT_EQ(7, key.target_size().width());
- EXPECT_EQ(3, key.target_size().height());
- EXPECT_EQ(7u * 3u * 4u, key.locked_bytes());
+ EXPECT_EQ(8, key.target_size().width());
+ EXPECT_EQ(4, key.target_size().height());
+ EXPECT_EQ(8u * 4u * 4u, key.locked_bytes());
}
TEST(SoftwareImageDecodeCacheTest,
@@ -477,9 +477,9 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToMediumIfTooLarge) {
draw_image, kN32_SkColorType);
EXPECT_EQ(draw_image.frame_key(), key.frame_key());
EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale);
- EXPECT_EQ(2277, key.target_size().width());
+ EXPECT_EQ(2278, key.target_size().width());
EXPECT_EQ(1024, key.target_size().height());
- EXPECT_EQ(2277u * 1024u * 4u, key.locked_bytes());
+ EXPECT_EQ(2278u * 1024u * 4u, key.locked_bytes());
}
TEST(SoftwareImageDecodeCacheTest,
@@ -1445,7 +1445,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_1ScaleIsHandled) {
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
EXPECT_EQ(kLow_SkFilterQuality, decoded_draw_image.filter_quality());
- EXPECT_EQ(62, decoded_draw_image.image()->width());
+ EXPECT_EQ(63, decoded_draw_image.image()->width());
EXPECT_EQ(25, decoded_draw_image.image()->height());
cache.DrawWithImageFinished(draw_image, decoded_draw_image);
@@ -1476,8 +1476,8 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_01ScaleIsHandled) {
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
EXPECT_EQ(kLow_SkFilterQuality, decoded_draw_image.filter_quality());
- EXPECT_EQ(7, decoded_draw_image.image()->width());
- EXPECT_EQ(3, decoded_draw_image.image()->height());
+ EXPECT_EQ(8, decoded_draw_image.image()->width());
+ EXPECT_EQ(4, decoded_draw_image.image()->height());
cache.DrawWithImageFinished(draw_image, decoded_draw_image);
cache.UnrefImage(draw_image);
@@ -1734,12 +1734,8 @@ TEST(SoftwareImageDecodeCacheTest, BitmapImageNotColorConverted) {
quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultColorSpace());
- DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
- // Expect that we did not allocate a new image.
- EXPECT_EQ(decoded_draw_image.image().get(), paint_image.GetSkImage().get());
-
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+ // The cache should not support this image.
+ EXPECT_FALSE(cache.UseCacheForDrawImage(draw_image));
}
// TODO(ccameron): Re-enable this when the root cause of crashes is discovered.
@@ -1777,5 +1773,138 @@ TEST(SoftwareImageDecodeCacheTest, DISABLED_ContentIdCaching) {
}
}
+TEST(SoftwareImageDecodeCacheTest, DecodeToScale) {
+ TestSoftwareImageDecodeCache cache;
+ bool is_decomposable = true;
+ SkFilterQuality quality = kMedium_SkFilterQuality;
+
+ SkISize full_size = SkISize::Make(100, 100);
+ std::vector<SkISize> supported_sizes = {SkISize::Make(25, 25),
+ SkISize::Make(50, 50)};
+ std::vector<FrameMetadata> frames = {FrameMetadata()};
+ sk_sp<FakePaintImageGenerator> generator =
+ sk_make_sp<FakePaintImageGenerator>(
+ SkImageInfo::MakeN32Premul(full_size.width(), full_size.height(),
+ DefaultColorSpace().ToSkColorSpace()),
+ frames, true, supported_sizes);
+ PaintImage paint_image = PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_frame_index(0u)
+ .TakePaintImage();
+
+ // Scale to mip level 1, there should be a single entry in the cache from
+ // the direct decode.
+ DrawImage draw_image1(
+ paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
+ quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
+ PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DecodedDrawImage decoded_image1 = cache.GetDecodedImageForDraw(draw_image1);
+ ASSERT_TRUE(decoded_image1.image());
+ EXPECT_EQ(decoded_image1.image()->width(), 50);
+ EXPECT_EQ(decoded_image1.image()->height(), 50);
+ EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 1u);
+
+ // We should have requested a scaled decode from the generator.
+ ASSERT_EQ(generator->decode_infos().size(), 1u);
+ EXPECT_EQ(generator->decode_infos().at(0).width(), 50);
+ EXPECT_EQ(generator->decode_infos().at(0).height(), 50);
+
+ // Scale to mip level 2, we should be using the existing entry instead of
+ // re-decoding.
+ DrawImage draw_image2(
+ paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
+ quality, CreateMatrix(SkSize::Make(0.25, 0.25), is_decomposable),
+ PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DecodedDrawImage decoded_image2 = cache.GetDecodedImageForDraw(draw_image2);
+ ASSERT_TRUE(decoded_image2.image());
+ EXPECT_EQ(decoded_image2.image()->width(), 25);
+ EXPECT_EQ(decoded_image2.image()->height(), 25);
+ EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 2u);
+
+ // Since we scaled from the existing entry, no new decodes should be
+ // requested from the generator.
+ ASSERT_EQ(generator->decode_infos().size(), 1u);
+ EXPECT_EQ(generator->decode_infos().at(0).width(), 50);
+ EXPECT_EQ(generator->decode_infos().at(0).height(), 50);
+
+ cache.DrawWithImageFinished(draw_image1, decoded_image1);
+ cache.DrawWithImageFinished(draw_image2, decoded_image2);
+}
+
+TEST(SoftwareImageDecodeCacheTest, DecodeToScaleSubrect) {
+ TestSoftwareImageDecodeCache cache;
+ bool is_decomposable = true;
+ SkFilterQuality quality = kMedium_SkFilterQuality;
+
+ SkISize full_size = SkISize::Make(100, 100);
+ std::vector<SkISize> supported_sizes = {SkISize::Make(25, 25),
+ SkISize::Make(50, 50)};
+ std::vector<FrameMetadata> frames = {FrameMetadata()};
+ sk_sp<FakePaintImageGenerator> generator =
+ sk_make_sp<FakePaintImageGenerator>(
+ SkImageInfo::MakeN32Premul(full_size.width(), full_size.height(),
+ DefaultColorSpace().ToSkColorSpace()),
+ frames, true, supported_sizes);
+ PaintImage paint_image = PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_frame_index(0u)
+ .TakePaintImage();
+
+ // Scale to mip level 1, there should be 2 entries in the cache, since the
+ // subrect vetoes decode to scale.
+ DrawImage draw_image(paint_image, SkIRect::MakeWH(50, 50), quality,
+ CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
+ PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+ DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image);
+ ASSERT_TRUE(decoded_image.image());
+ EXPECT_EQ(decoded_image.image()->width(), 25);
+ EXPECT_EQ(decoded_image.image()->height(), 25);
+ EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 2u);
+
+ // We should have requested the original decode from the generator.
+ ASSERT_EQ(generator->decode_infos().size(), 1u);
+ EXPECT_EQ(generator->decode_infos().at(0).width(), 100);
+ EXPECT_EQ(generator->decode_infos().at(0).height(), 100);
+ cache.DrawWithImageFinished(draw_image, decoded_image);
+}
+
+TEST(SoftwareImageDecodeCacheTest, DecodeToScaleNoneQuality) {
+ TestSoftwareImageDecodeCache cache;
+ bool is_decomposable = true;
+ SkFilterQuality quality = kNone_SkFilterQuality;
+
+ SkISize full_size = SkISize::Make(100, 100);
+ std::vector<SkISize> supported_sizes = {SkISize::Make(25, 25),
+ SkISize::Make(50, 50)};
+ std::vector<FrameMetadata> frames = {FrameMetadata()};
+ sk_sp<FakePaintImageGenerator> generator =
+ sk_make_sp<FakePaintImageGenerator>(
+ SkImageInfo::MakeN32Premul(full_size.width(), full_size.height(),
+ DefaultColorSpace().ToSkColorSpace()),
+ frames, true, supported_sizes);
+ PaintImage paint_image = PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_frame_index(0u)
+ .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());
+ DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image);
+ ASSERT_TRUE(decoded_image.image());
+ EXPECT_EQ(decoded_image.image()->width(), 100);
+ EXPECT_EQ(decoded_image.image()->height(), 100);
+
+ // We should have requested the original decode from the generator.
+ ASSERT_EQ(generator->decode_infos().size(), 1u);
+ EXPECT_EQ(generator->decode_infos().at(0).width(), 100);
+ EXPECT_EQ(generator->decode_infos().at(0).height(), 100);
+ cache.DrawWithImageFinished(draw_image, decoded_image);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.cc b/chromium/cc/tiles/software_image_decode_cache_utils.cc
index 4b6016b4126..565a0ffbc45 100644
--- a/chromium/cc/tiles/software_image_decode_cache_utils.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_utils.cc
@@ -71,7 +71,6 @@ SoftwareImageDecodeCacheUtils::DoDecodeImage(const CacheKey& key,
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"SoftwareImageDecodeCacheUtils::DoDecodeImage - "
"decode");
- DCHECK_EQ(key.type(), CacheKey::kOriginal);
bool result = paint_image.Decode(target_pixels->data(), &target_info,
key.target_color_space().ToSkColorSpace(),
key.frame_key().frame_index());
diff --git a/chromium/cc/tiles/tile_manager_perftest.cc b/chromium/cc/tiles/tile_manager_perftest.cc
index 6bb3562ab13..8b30a30b947 100644
--- a/chromium/cc/tiles/tile_manager_perftest.cc
+++ b/chromium/cc/tiles/tile_manager_perftest.cc
@@ -45,9 +45,9 @@ class TileManagerPerfTest : public TestLayerTreeHostBase {
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval) {}
- void InitializeRenderer() override {
+ void InitializeFrameSink() override {
host_impl()->SetVisible(true);
- host_impl()->InitializeRenderer(layer_tree_frame_sink());
+ host_impl()->InitializeFrameSink(layer_tree_frame_sink());
tile_manager()->SetTileTaskManagerForTesting(
std::make_unique<FakeTileTaskManagerImpl>());
}
diff --git a/chromium/cc/trees/animation_options.h b/chromium/cc/trees/animation_options.h
new file mode 100644
index 00000000000..bce98cda7dc
--- /dev/null
+++ b/chromium/cc/trees/animation_options.h
@@ -0,0 +1,25 @@
+// 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_TREES_ANIMATION_OPTIONS_H_
+#define CC_TREES_ANIMATION_OPTIONS_H_
+
+#include <memory>
+
+#include "cc/cc_export.h"
+
+namespace cc {
+
+// This class acts as opaque handle in cc while the actual implementation lives
+// in blink. It is meant to facilitate plumbing the options from blink main
+// thread to worklet thread via cc animations machinery.
+class CC_EXPORT AnimationOptions {
+ public:
+ virtual ~AnimationOptions() = default;
+ virtual std::unique_ptr<AnimationOptions> Clone() const = 0;
+};
+
+} // namespace cc
+
+#endif // CC_TREES_ANIMATION_OPTIONS_H_
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
index b888d085203..1628a53c0c6 100644
--- a/chromium/cc/trees/draw_property_utils.cc
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -13,6 +13,7 @@
#include "cc/layers/draw_properties.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
+#include "cc/layers/picture_layer.h"
#include "cc/trees/clip_node.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_impl.h"
@@ -490,53 +491,6 @@ static void UpdateElasticOverscrollInternal(
property_trees->transform_tree.set_needs_update(true);
}
-#if DCHECK_IS_ON()
-static void ValidatePageScaleLayer(const Layer* page_scale_layer) {
- DCHECK_EQ(page_scale_layer->position().ToString(), gfx::PointF().ToString());
- DCHECK_EQ(page_scale_layer->transform_origin().ToString(),
- gfx::Point3F().ToString());
-}
-
-static void ValidatePageScaleLayer(const LayerImpl* page_scale_layer) {}
-#endif
-
-template <typename LayerType>
-static void UpdatePageScaleFactorInternal(PropertyTrees* property_trees,
- const LayerType* page_scale_layer,
- float page_scale_factor,
- float device_scale_factor,
- gfx::Transform device_transform) {
- if (property_trees->transform_tree.page_scale_factor() == page_scale_factor ||
- !page_scale_layer) {
- return;
- }
-
- property_trees->transform_tree.set_page_scale_factor(page_scale_factor);
- DCHECK_GE(page_scale_layer->transform_tree_index(),
- TransformTree::kRootNodeId);
- TransformNode* node = property_trees->transform_tree.Node(
- page_scale_layer->transform_tree_index());
-// TODO(enne): property trees can't ask the layer these things, but
-// the page scale layer should *just* be the page scale.
-#if DCHECK_IS_ON()
- ValidatePageScaleLayer(page_scale_layer);
-#endif
-
- if (IsRootLayer(page_scale_layer)) {
- // When the page scale layer is also the root layer, the node should also
- // store the combined scale factor and not just the page scale factor.
- float post_local_scale_factor = page_scale_factor * device_scale_factor;
- node->post_local_scale_factor = post_local_scale_factor;
- node->post_local = device_transform;
- node->post_local.Scale(post_local_scale_factor, post_local_scale_factor);
- } else {
- node->post_local_scale_factor = page_scale_factor;
- node->update_post_local_transform(gfx::PointF(), gfx::Point3F());
- }
- node->needs_local_transform_update = true;
- property_trees->transform_tree.set_needs_update(true);
-}
-
static gfx::Rect LayerDrawableContentRect(
const LayerImpl* layer,
const gfx::Rect& layer_bounds_in_target_space,
@@ -609,7 +563,7 @@ static gfx::Transform ScreenSpaceTransformInternal(LayerType* layer,
layer->offset_to_transform_parent().y());
gfx::Transform ssxform = tree.ToScreen(layer->transform_tree_index());
xform.ConcatTransform(ssxform);
- if (layer->should_flatten_transform_from_property_tree())
+ if (layer->should_flatten_screen_space_transform_from_property_tree())
xform.FlattenTo2d();
return xform;
}
@@ -821,7 +775,7 @@ void FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host,
// Append mask layers to the update layer list. They don't have valid
// visible rects, so need to get added after the above calculation.
- if (Layer* mask_layer = layer->mask_layer()) {
+ if (PictureLayer* mask_layer = layer->mask_layer()) {
// Layers with empty bounds should never be painted, including masks.
if (!mask_layer->bounds().IsEmpty())
update_layer_list->push_back(mask_layer);
@@ -935,7 +889,7 @@ gfx::Transform DrawTransform(const LayerImpl* layer,
transform_tree.property_trees()->GetToTarget(
layer->transform_tree_index(), layer->render_target_effect_tree_index(),
&xform);
- if (layer->should_flatten_transform_from_property_tree())
+ if (layer->should_flatten_screen_space_transform_from_property_tree())
xform.FlattenTo2d();
xform.Translate(layer->offset_to_transform_parent().x(),
layer->offset_to_transform_parent().y());
@@ -1047,23 +1001,27 @@ void ComputeSurfaceDrawProperties(PropertyTrees* property_trees,
}
void UpdatePageScaleFactor(PropertyTrees* property_trees,
- const LayerImpl* page_scale_layer,
+ TransformNode* page_scale_node,
float page_scale_factor,
float device_scale_factor,
const gfx::Transform device_transform) {
- UpdatePageScaleFactorInternal(property_trees, page_scale_layer,
- page_scale_factor, device_scale_factor,
- device_transform);
-}
+ // TODO(wjmaclean): Once Issue #845097 is resolved, we can change the nullptr
+ // check below to a DCHECK.
+ if (property_trees->transform_tree.page_scale_factor() == page_scale_factor ||
+ !page_scale_node) {
+ return;
+ }
-void UpdatePageScaleFactor(PropertyTrees* property_trees,
- const Layer* page_scale_layer,
- float page_scale_factor,
- float device_scale_factor,
- const gfx::Transform device_transform) {
- UpdatePageScaleFactorInternal(property_trees, page_scale_layer,
- page_scale_factor, device_scale_factor,
- device_transform);
+ property_trees->transform_tree.set_page_scale_factor(page_scale_factor);
+
+ float post_local_scale_factor = page_scale_factor * device_scale_factor;
+ page_scale_node->post_local_scale_factor = post_local_scale_factor;
+ page_scale_node->post_local = device_transform;
+ page_scale_node->post_local.Scale(post_local_scale_factor,
+ post_local_scale_factor);
+
+ page_scale_node->needs_local_transform_update = true;
+ property_trees->transform_tree.set_needs_update(true);
}
void UpdateElasticOverscroll(PropertyTrees* property_trees,
diff --git a/chromium/cc/trees/draw_property_utils.h b/chromium/cc/trees/draw_property_utils.h
index 6c843521df6..af88fbf17a4 100644
--- a/chromium/cc/trees/draw_property_utils.h
+++ b/chromium/cc/trees/draw_property_utils.h
@@ -24,6 +24,7 @@ class EffectTree;
class TransformTree;
class PropertyTrees;
struct EffectNode;
+struct TransformNode;
namespace draw_property_utils {
@@ -88,13 +89,7 @@ gfx::Transform CC_EXPORT ScreenSpaceTransform(const LayerImpl* layer,
const TransformTree& tree);
void CC_EXPORT UpdatePageScaleFactor(PropertyTrees* property_trees,
- const LayerImpl* page_scale_layer,
- float page_scale_factor,
- float device_scale_factor,
- const gfx::Transform device_transform);
-
-void CC_EXPORT UpdatePageScaleFactor(PropertyTrees* property_trees,
- const Layer* page_scale_layer,
+ TransformNode* page_scale_node,
float page_scale_factor,
float device_scale_factor,
const gfx::Transform device_transform);
diff --git a/chromium/cc/trees/element_id.cc b/chromium/cc/trees/element_id.cc
index fe33e57dfef..0603ba726c7 100644
--- a/chromium/cc/trees/element_id.cc
+++ b/chromium/cc/trees/element_id.cc
@@ -40,7 +40,7 @@ void ElementId::AddToTracedValue(base::trace_event::TracedValue* res) const {
res->EndDictionary();
}
-ElementIdType ElementId::ToInternalValue() const {
+ElementIdType ElementId::GetInternalValue() const {
return id_;
}
diff --git a/chromium/cc/trees/element_id.h b/chromium/cc/trees/element_id.h
index 6f456b1163e..1b581ba881c 100644
--- a/chromium/cc/trees/element_id.h
+++ b/chromium/cc/trees/element_id.h
@@ -60,9 +60,7 @@ struct CC_EXPORT ElementId {
void AddToTracedValue(base::trace_event::TracedValue* res) const;
std::unique_ptr<base::Value> AsValue() const;
- // Returns the element id as its underlying representation.
- // TODO(wkorman): Remove or rename this method. http://crbug.com/752327
- ElementIdType ToInternalValue() const;
+ ElementIdType GetInternalValue() const;
std::string ToString() const;
diff --git a/chromium/cc/trees/frame_rate_counter.cc b/chromium/cc/trees/frame_rate_counter.cc
index f801dbf640d..ac4d517f5d2 100644
--- a/chromium/cc/trees/frame_rate_counter.cc
+++ b/chromium/cc/trees/frame_rate_counter.cc
@@ -57,18 +57,6 @@ void FrameRateCounter::SaveTimeStamp(base::TimeTicks timestamp, bool software) {
base::TimeDelta frame_interval_seconds =
RecentFrameInterval(ring_buffer_.BufferSize() - 1);
- if (has_impl_thread_ && ring_buffer_.CurrentIndex() > 0) {
- if (software) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.SoftwareCompositorThreadImplDrawDelay",
- frame_interval_seconds.InMilliseconds(), 1, 120, 60);
- } else {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CompositorThreadImplDrawDelay",
- frame_interval_seconds.InMilliseconds(), 1,
- 120, 60);
- }
- }
-
if (!IsBadFrameInterval(frame_interval_seconds) &&
frame_interval_seconds.InSecondsF() > kDroppedFrameTime)
dropped_frame_count_ +=
diff --git a/chromium/cc/trees/frame_token_allocator.cc b/chromium/cc/trees/frame_token_allocator.cc
deleted file mode 100644
index 4f6ec1cf91c..00000000000
--- a/chromium/cc/trees/frame_token_allocator.cc
+++ /dev/null
@@ -1,26 +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/trees/frame_token_allocator.h"
-
-namespace cc {
-
-uint32_t FrameTokenAllocator::GetOrAllocateFrameToken() {
- if (frame_token_allocated_)
- return frame_token_;
- frame_token_allocated_ = true;
-
- // TODO(jonross) we will want to have a wrapping strategy to handle overflow.
- // We will also want to confirm this looping behaviour in processes which
- // receive the token.
- return ++frame_token_;
-}
-
-uint32_t FrameTokenAllocator::GetFrameTokenForSubmission() {
- uint32_t result = frame_token_allocated_ ? frame_token_ : 0;
- frame_token_allocated_ = false;
- return result;
-}
-
-} // namespace cc
diff --git a/chromium/cc/trees/frame_token_allocator.h b/chromium/cc/trees/frame_token_allocator.h
deleted file mode 100644
index 1bb978d631f..00000000000
--- a/chromium/cc/trees/frame_token_allocator.h
+++ /dev/null
@@ -1,52 +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_TREES_FRAME_TOKEN_ALLOCATOR_H_
-#define CC_TREES_FRAME_TOKEN_ALLOCATOR_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "cc/cc_export.h"
-
-namespace cc {
-
-// For some compositor frame submissions, there is additional work which a frame
-// embedder wishes to perform only after the frame has been processed by the
-// display compositor.
-//
-// For this a FrameToken is sent both with the compositor frame submission, as
-// well as with messages to the embedder.
-//
-// However for any given frame there are multiple possible sources which may
-// wish to increment the FrameToken. FrameTokenAllocator is a shared source of
-// these tokens, only ever increasing the token once during a given frame
-// submission.
-class CC_EXPORT FrameTokenAllocator {
- public:
- FrameTokenAllocator() = default;
- virtual ~FrameTokenAllocator() = default;
-
- // During frame submission the first call to this allocates and returns a new
- // frame token. All subsequent calls return the current frame token.
- uint32_t GetOrAllocateFrameToken();
-
- // Gets the token for the current frame submission, signifying the end of
- // frame submission. Or 0 is no token was allocated. The next call to
- // GetOrAllocateFrameToken will lead to the generation of a new frame token.
- uint32_t GetFrameTokenForSubmission();
-
- private:
- // True if a frame token is allocated during the current frame submission.
- bool frame_token_allocated_ = false;
-
- // The current frame token.
- uint32_t frame_token_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(FrameTokenAllocator);
-};
-
-} // namespace cc
-
-#endif // CC_TREES_FRAME_TOKEN_ALLOCATOR_H_
diff --git a/chromium/cc/trees/latency_info_swap_promise.cc b/chromium/cc/trees/latency_info_swap_promise.cc
index 9b376030ed5..208582c6e3e 100644
--- a/chromium/cc/trees/latency_info_swap_promise.cc
+++ b/chromium/cc/trees/latency_info_swap_promise.cc
@@ -9,23 +9,6 @@
#include "base/logging.h"
#include "base/trace_event/trace_event.h"
-namespace {
-ui::LatencyComponentType DidNotSwapReasonToLatencyComponentType(
- cc::SwapPromise::DidNotSwapReason reason) {
- switch (reason) {
- case cc::SwapPromise::ACTIVATION_FAILS:
- case cc::SwapPromise::SWAP_FAILS:
- return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT;
- case cc::SwapPromise::COMMIT_FAILS:
- return ui::INPUT_EVENT_LATENCY_TERMINATED_COMMIT_FAILED_COMPONENT;
- case cc::SwapPromise::COMMIT_NO_UPDATE:
- return ui::INPUT_EVENT_LATENCY_TERMINATED_COMMIT_NO_UPDATE_COMPONENT;
- }
- NOTREACHED() << "Unhandled DidNotSwapReason.";
- return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT;
-}
-} // namespace
-
namespace cc {
LatencyInfoSwapPromise::LatencyInfoSwapPromise(const ui::LatencyInfo& latency)
@@ -33,22 +16,18 @@ LatencyInfoSwapPromise::LatencyInfoSwapPromise(const ui::LatencyInfo& latency)
LatencyInfoSwapPromise::~LatencyInfoSwapPromise() = default;
-void LatencyInfoSwapPromise::WillSwap(
- viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator) {
+void LatencyInfoSwapPromise::WillSwap(viz::CompositorFrameMetadata* metadata) {
DCHECK(!latency_.terminated());
metadata->latency_info.push_back(latency_);
}
void LatencyInfoSwapPromise::DidSwap() {}
-SwapPromise::DidNotSwapAction LatencyInfoSwapPromise::DidNotSwap(
- DidNotSwapReason reason) {
- latency_.AddLatencyNumber(DidNotSwapReasonToLatencyComponentType(reason), 0);
+void LatencyInfoSwapPromise::DidNotSwap(DidNotSwapReason reason) {
+ latency_.Terminate();
// TODO(miletus): Turn this back on once per-event LatencyInfo tracking
// is enabled in GPU side.
// DCHECK(latency_.terminated);
- return DidNotSwapAction::BREAK_PROMISE;
}
int64_t LatencyInfoSwapPromise::TraceId() const {
diff --git a/chromium/cc/trees/latency_info_swap_promise.h b/chromium/cc/trees/latency_info_swap_promise.h
index bdccb3eb546..2f2fdee234a 100644
--- a/chromium/cc/trees/latency_info_swap_promise.h
+++ b/chromium/cc/trees/latency_info_swap_promise.h
@@ -19,10 +19,9 @@ class CC_EXPORT LatencyInfoSwapPromise : public SwapPromise {
~LatencyInfoSwapPromise() override;
void DidActivate() override {}
- void WillSwap(viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator) override;
+ void WillSwap(viz::CompositorFrameMetadata* metadata) override;
void DidSwap() override;
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override;
+ void DidNotSwap(DidNotSwapReason reason) override;
void OnCommit() override;
int64_t TraceId() const override;
diff --git a/chromium/cc/trees/latency_info_swap_promise_monitor.cc b/chromium/cc/trees/latency_info_swap_promise_monitor.cc
index 99ec2c686a4..5da4b6895b3 100644
--- a/chromium/cc/trees/latency_info_swap_promise_monitor.cc
+++ b/chromium/cc/trees/latency_info_swap_promise_monitor.cc
@@ -19,19 +19,19 @@ bool AddRenderingScheduledComponent(ui::LatencyInfo* latency_info,
ui::LatencyComponentType type =
on_main ? ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT
: ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT;
- if (latency_info->FindLatency(type, 0, nullptr))
+ if (latency_info->FindLatency(type, nullptr))
return false;
- latency_info->AddLatencyNumber(type, 0);
+ latency_info->AddLatencyNumber(type);
return true;
}
bool AddForwardingScrollUpdateToMainComponent(ui::LatencyInfo* latency_info) {
if (latency_info->FindLatency(
- ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT, 0,
+ ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT,
nullptr))
return false;
latency_info->AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT, 0);
+ ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT);
return true;
}
@@ -74,7 +74,7 @@ void LatencyInfoSwapPromiseMonitor::OnForwardScrollUpdateToMainThreadOnImpl() {
*latency_,
ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT);
new_latency.AddLatencyNumberWithTraceName(
- ui::LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT, 0,
+ ui::LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT,
"ScrollUpdate");
std::unique_ptr<SwapPromise> swap_promise(
new LatencyInfoSwapPromise(new_latency));
diff --git a/chromium/cc/trees/layer_tree_frame_sink.h b/chromium/cc/trees/layer_tree_frame_sink.h
index 7f550dc9fe8..edbdd247f15 100644
--- a/chromium/cc/trees/layer_tree_frame_sink.h
+++ b/chromium/cc/trees/layer_tree_frame_sink.h
@@ -14,11 +14,11 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "cc/cc_export.h"
+#include "components/viz/client/shared_bitmap_reporter.h"
#include "components/viz/common/gpu/context_lost_observer.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "components/viz/common/resources/returned_resource.h"
-#include "components/viz/common/resources/shared_bitmap_reporter.h"
#include "gpu/command_buffer/common/texture_in_use_response.h"
#include "ui/gfx/color_space.h"
@@ -44,21 +44,6 @@ class LayerTreeFrameSinkClient;
class CC_EXPORT LayerTreeFrameSink : public viz::SharedBitmapReporter,
public viz::ContextLostObserver {
public:
- struct Capabilities {
- Capabilities() = default;
-
- // True if we must always swap, even if there is no damage to the frame.
- // Needed for both the browser compositor as well as layout tests.
- // TODO(ericrk): This should be test-only for layout tests, but tab
- // capture has issues capturing offscreen tabs whithout this. We should
- // remove this dependency. crbug.com/680196
- bool must_always_swap = false;
-
- // True if sync points for resources are needed when swapping delegated
- // frames.
- bool delegated_sync_points_required = true;
- };
-
// Constructor for GL-based and/or software resources.
//
// |compositor_task_runner| is used to post worker context lost callback and
@@ -96,8 +81,6 @@ class CC_EXPORT LayerTreeFrameSink : public viz::SharedBitmapReporter,
bool HasClient() { return !!client_; }
- const Capabilities& capabilities() const { return capabilities_; }
-
// The viz::ContextProviders may be null if frames should be submitted with
// software SharedMemory resources.
viz::ContextProvider* context_provider() const {
@@ -116,8 +99,9 @@ class CC_EXPORT LayerTreeFrameSink : public viz::SharedBitmapReporter,
// Support for a pull-model where draws are requested by the implementation of
// LayerTreeFrameSink. This is called by the compositor to notify that there's
- // new content.
- virtual void Invalidate() {}
+ // new content. Can be called when nothing needs to be drawn if tile
+ // priorities should be updated.
+ virtual void Invalidate(bool needs_draw) {}
// For successful swaps, the implementation must call
// DidReceiveCompositorFrameAck() asynchronously when the frame has been
@@ -141,7 +125,6 @@ class CC_EXPORT LayerTreeFrameSink : public viz::SharedBitmapReporter,
LayerTreeFrameSinkClient* client_ = nullptr;
- struct LayerTreeFrameSink::Capabilities capabilities_;
scoped_refptr<viz::ContextProvider> context_provider_;
scoped_refptr<viz::RasterContextProvider> worker_context_provider_;
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
diff --git a/chromium/cc/trees/layer_tree_frame_sink_client.h b/chromium/cc/trees/layer_tree_frame_sink_client.h
index d774db56e35..87fc6b8b11e 100644
--- a/chromium/cc/trees/layer_tree_frame_sink_client.h
+++ b/chromium/cc/trees/layer_tree_frame_sink_client.h
@@ -15,6 +15,7 @@
#include "ui/gfx/geometry/rect.h"
namespace gfx {
+struct PresentationFeedback;
class Transform;
}
@@ -58,12 +59,9 @@ class CC_EXPORT LayerTreeFrameSinkClient {
// See ui/gfx/presentation_feedback.h for details on args. |time| is always
// non-zero.
- virtual void DidPresentCompositorFrame(uint32_t presentation_token,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) = 0;
-
- virtual void DidDiscardCompositorFrame(uint32_t presentation_token) = 0;
+ virtual void DidPresentCompositorFrame(
+ uint32_t presentation_token,
+ const gfx::PresentationFeedback& feedback) = 0;
// The LayerTreeFrameSink is lost when the viz::ContextProviders held by it
// encounter an error. In this case the LayerTreeFrameSink (and the
@@ -74,7 +72,8 @@ class CC_EXPORT LayerTreeFrameSinkClient {
// a new CompositorFrame synchronously.
virtual void OnDraw(const gfx::Transform& transform,
const gfx::Rect& viewport,
- bool resourceless_software_draw) = 0;
+ bool resourceless_software_draw,
+ bool skip_draw) = 0;
// For SynchronousCompositor (WebView) to set how much memory the compositor
// can use without changing visibility.
diff --git a/chromium/cc/trees/layer_tree_frame_sink_unittest.cc b/chromium/cc/trees/layer_tree_frame_sink_unittest.cc
index 781effb7740..355b818c48b 100644
--- a/chromium/cc/trees/layer_tree_frame_sink_unittest.cc
+++ b/chromium/cc/trees/layer_tree_frame_sink_unittest.cc
@@ -9,7 +9,7 @@
#include "cc/test/fake_layer_tree_frame_sink_client.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/test/test_context_provider.h"
-#include "components/viz/test/test_web_graphics_context_3d.h"
+#include "components/viz/test/test_gles2_interface.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -66,7 +66,7 @@ TEST(LayerTreeFrameSinkTest, ContextLossFailsBind) {
viz::TestContextProvider::CreateWorker();
// Lose the context so BindToClient fails.
- context_provider->UnboundTestContext3d()->set_context_lost(true);
+ context_provider->UnboundTestContextGL()->set_context_lost(true);
auto task_runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
StubLayerTreeFrameSink layer_tree_frame_sink(context_provider,
@@ -112,7 +112,7 @@ TEST(LayerTreeFrameSinkTest, WorkerContextLossFailsBind) {
viz::TestContextProvider::CreateWorker();
// Lose the context so BindToClient fails.
- worker_provider->UnboundTestContext3d()->set_context_lost(true);
+ worker_provider->UnboundTestContextGL()->set_context_lost(true);
auto task_runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
StubLayerTreeFrameSink layer_tree_frame_sink(context_provider,
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index b47182219c0..09f2fe5e574 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -16,6 +16,7 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/json/json_writer.h"
#include "base/location.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
@@ -61,6 +62,7 @@
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/presentation_feedback.h"
namespace {
static base::AtomicSequenceNumber s_layer_tree_host_sequence_number;
@@ -265,10 +267,6 @@ void LayerTreeHost::BeginMainFrame(const viz::BeginFrameArgs& args) {
client_->BeginMainFrame(args);
}
-void LayerTreeHost::DidStopFlinging() {
- proxy_->MainThreadHasStoppedFlinging();
-}
-
const LayerTreeDebugState& LayerTreeHost::GetDebugState() const {
return debug_state_;
}
@@ -299,32 +297,21 @@ void LayerTreeHost::FinishCommitOnImplThread(
}
sync_tree->set_source_frame_number(SourceFrameNumber());
-
- // Set presentation token if any pending .
- bool request_presentation_time = settings_.always_request_presentation_time;
- if (!pending_presentation_time_callbacks_.empty()) {
- request_presentation_time = true;
- frame_to_presentation_time_callbacks_[SourceFrameNumber()] =
- std::move(pending_presentation_time_callbacks_);
- pending_presentation_time_callbacks_.clear();
- } else if (!frame_to_presentation_time_callbacks_.empty()) {
- // There are pending callbacks. Keep requesting the presentation callback
- // in case a previous frame was dropped (the callbacks run when the frame
- // makes it to screen).
- request_presentation_time = true;
- }
- sync_tree->set_request_presentation_time(request_presentation_time);
+ bool request_presentation_time =
+ settings_.always_request_presentation_time ||
+ !pending_presentation_time_callbacks_.empty();
+ if (request_presentation_time && pending_presentation_time_callbacks_.empty())
+ pending_presentation_time_callbacks_.push_back(base::DoNothing());
+ sync_tree->AddPresentationCallbacks(
+ std::move(pending_presentation_time_callbacks_));
if (needs_full_tree_sync_)
TreeSynchronizer::SynchronizeTrees(root_layer(), sync_tree);
- // Track the navigation state before pushing properties since it overwrites
- // the |content_source_id_| on the sync tree.
- bool did_navigate = content_source_id_ != sync_tree->content_source_id();
- if (did_navigate) {
- TRACE_EVENT0("cc,benchmark", "LayerTreeHost::DidNavigate");
- proxy_->ClearHistoryOnNavigation();
- host_impl->DidNavigate();
+ if (clear_caches_on_next_commit_) {
+ clear_caches_on_next_commit_ = false;
+ proxy_->ClearHistory();
+ host_impl->ClearCaches();
}
{
@@ -333,7 +320,7 @@ void LayerTreeHost::FinishCommitOnImplThread(
PushPropertyTreesTo(sync_tree);
sync_tree->lifecycle().AdvanceTo(LayerTreeLifecycle::kSyncedPropertyTrees);
- PushSurfaceIdsTo(sync_tree);
+ PushSurfaceRangesTo(sync_tree);
TreeSynchronizer::PushLayerProperties(this, sync_tree);
sync_tree->lifecycle().AdvanceTo(
LayerTreeLifecycle::kSyncedLayerProperties);
@@ -546,6 +533,10 @@ void LayerTreeHost::SetNeedsCommit() {
swap_promise_manager_.NotifySwapPromiseMonitorsOfSetNeedsCommit();
}
+bool LayerTreeHost::RequestedMainFramePending() {
+ return proxy_->RequestedAnimatePending();
+}
+
void LayerTreeHost::SetNeedsRecalculateRasterScales() {
next_commit_forces_recalculate_raster_scales_ = true;
proxy_->SetNeedsCommit();
@@ -647,20 +638,6 @@ void LayerTreeHost::Composite(base::TimeTicks frame_begin_time, bool raster) {
proxy->CompositeImmediately(frame_begin_time, raster);
}
-static int GetLayersUpdateTimeHistogramBucket(size_t numLayers) {
- // We uses the following exponential (ratio 2) bucketization:
- // [0, 10), [10, 30), [30, 70), [70, 150), [150, infinity)
- if (numLayers < 10)
- return 0;
- if (numLayers < 30)
- return 1;
- if (numLayers < 70)
- return 2;
- if (numLayers < 150)
- return 3;
- return 4;
-}
-
bool LayerTreeHost::UpdateLayers() {
if (!root_layer()) {
property_trees_.clear();
@@ -678,30 +655,18 @@ bool LayerTreeHost::UpdateLayers() {
std::string histogram_name =
base::StringPrintf("Compositing.%s.LayersUpdateTime", client_name);
base::UmaHistogramCounts10M(histogram_name, elapsed);
-
- // Also add UpdateLayers metrics bucketed by the layer count.
- base::StringAppendF(&histogram_name, ".%d",
- GetLayersUpdateTimeHistogramBucket(NumLayers()));
- base::UmaHistogramCounts10M(histogram_name, elapsed);
}
return result;
}
void LayerTreeHost::DidPresentCompositorFrame(
- const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) {
- for (int frame : source_frames) {
- if (!frame_to_presentation_time_callbacks_.count(frame))
- continue;
-
- for (auto& callback : frame_to_presentation_time_callbacks_[frame])
- std::move(callback).Run(time, refresh, flags);
-
- frame_to_presentation_time_callbacks_.erase(frame);
- }
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback) {
+ for (auto& callback : callbacks)
+ std::move(callback).Run(feedback);
+ client_->DidPresentCompositorFrame(frame_token, feedback);
}
void LayerTreeHost::DidCompletePageScaleAnimation() {
@@ -803,23 +768,51 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) {
property_trees->AsTracedValue());
}
+#if DCHECK_IS_ON()
+ // Ensure property tree nodes were created for all layers. When using layer
+ // lists, this can fail if blink doesn't setup layers or nodes correctly in
+ // |PaintArtifactCompositor|. When not using layer lists, this can fail if
+ // |PropertyTreeBuilder::BuildPropertyTrees| fails to create property tree
+ // nodes.
+ for (auto* layer : *this) {
+ DCHECK(property_trees_.effect_tree.Node(layer->effect_tree_index()));
+ DCHECK(
+ property_trees_.transform_tree.Node(layer->transform_tree_index()));
+ DCHECK(property_trees_.clip_tree.Node(layer->clip_tree_index()));
+ DCHECK(property_trees_.scroll_tree.Node(layer->scroll_tree_index()));
+ }
+#endif
+
draw_property_utils::UpdatePropertyTrees(this, property_trees);
draw_property_utils::FindLayersThatNeedUpdates(this, property_trees,
&update_layer_list);
+
+ // Dump property trees useful for debugging --blink-gen-property-trees
+ // flag. We care only about the renderer compositor.
+ if (VLOG_IS_ON(3) && GetClientNameForMetrics() == std::string("Renderer")) {
+ VLOG(3) << "CC Property Trees:";
+ std::string out;
+ base::JSONWriter::WriteWithOptions(
+ *property_trees->AsTracedValue()->ToBaseValue(),
+ base::JSONWriter::OPTIONS_PRETTY_PRINT, &out);
+ VLOG(3) << out;
+ }
}
- bool content_has_slow_paths = false;
- bool content_has_non_aa_paint = false;
- bool did_paint_content = PaintContent(
- update_layer_list, &content_has_slow_paths, &content_has_non_aa_paint);
+ bool painted_content_has_slow_paths = false;
+ bool painted_content_has_non_aa_paint = false;
+ bool did_paint_content =
+ PaintContent(update_layer_list, &painted_content_has_slow_paths,
+ &painted_content_has_non_aa_paint);
- // |content_has_non_aa_paint| is a correctness (not performance) modifier, if
- // it changes we immediately update. To prevent churn, this flag is sticky.
- content_has_non_aa_paint_ |= content_has_non_aa_paint;
+ // |painted_content_has_non_aa_paint| is a correctness (not performance)
+ // modifier, if it changes we immediately update. To prevent churn, this flag
+ // is sticky.
+ content_has_non_aa_paint_ |= painted_content_has_non_aa_paint;
// If no slow-path content has appeared for a required number of frames,
// update the flag.
- if (!content_has_slow_paths) {
+ if (!painted_content_has_slow_paths) {
++num_consecutive_frames_without_slow_paths_;
if (num_consecutive_frames_without_slow_paths_ >=
kNumFramesToConsiderBeforeRemovingSlowPathFlag) {
@@ -848,7 +841,7 @@ void LayerTreeHost::ApplyViewportDeltas(ScrollAndScaleSet* info) {
if (viewport_layers_.inner_viewport_scroll) {
viewport_layers_.inner_viewport_scroll->SetScrollOffsetFromImplSide(
gfx::ScrollOffsetWithDelta(
- viewport_layers_.inner_viewport_scroll->scroll_offset(),
+ viewport_layers_.inner_viewport_scroll->CurrentScrollOffset(),
inner_viewport_scroll_delta));
}
@@ -889,7 +882,7 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) {
if (!layer)
continue;
layer->SetScrollOffsetFromImplSide(gfx::ScrollOffsetWithDelta(
- layer->scroll_offset(), info->scrolls[i].scroll_delta));
+ layer->CurrentScrollOffset(), info->scrolls[i].scroll_delta));
SetNeedsUpdateLayers();
}
for (size_t i = 0; i < info->scrollbars.size(); ++i) {
@@ -923,10 +916,18 @@ void LayerTreeHost::UpdateBrowserControlsState(
}
void LayerTreeHost::AnimateLayers(base::TimeTicks monotonic_time) {
+ // We do not need to animate on the main thread in this case because all
+ // relevant changes will be processed on the compositor thread, or proxy,
+ // and propagated back to the correct trees.
+ // TODO(majidvp): We should be able to eliminate this in the non-
+ // slimming path and will do so in a follow up. (762717)
+ if (IsUsingLayerLists())
+ return;
+
std::unique_ptr<MutatorEvents> events = mutator_host_->CreateEvents();
if (mutator_host_->TickAnimations(monotonic_time,
- property_trees()->scroll_tree))
+ property_trees()->scroll_tree, true))
mutator_host_->UpdateAnimationState(true, events.get());
if (!events->IsEmpty())
@@ -1012,9 +1013,9 @@ void LayerTreeHost::RegisterViewportLayers(const ViewportLayers& layers) {
// overscroll elasticity (optional)
// page scale
// inner viewport scroll
- DCHECK(!layers.page_scale ||
+ DCHECK(IsUsingLayerLists() || !layers.page_scale ||
layers.inner_viewport_scroll->parent() == layers.page_scale);
- DCHECK(!layers.page_scale ||
+ DCHECK(IsUsingLayerLists() || !layers.page_scale ||
layers.page_scale->parent() == layers.overscroll_elasticity ||
layers.page_scale->parent() == layers.inner_viewport_container);
viewport_layers_.overscroll_elasticity = layers.overscroll_elasticity;
@@ -1048,6 +1049,22 @@ void LayerTreeHost::SetEventListenerProperties(
if (event_listener_properties_[index] == properties)
return;
+ // TODO(sunxd): Remove NeedsFullTreeSync when computing mouse wheel event
+ // handler region is done.
+ // We only do full tree sync if the mouse wheel event listener property
+ // changes from kNone/kPassive to kBlocking/kBlockingAndPassive.
+ if (event_class == EventListenerClass::kMouseWheel &&
+ !(event_listener_properties_[index] ==
+ EventListenerProperties::kBlocking ||
+ event_listener_properties_[index] ==
+ EventListenerProperties::kBlockingAndPassive) &&
+ (properties == EventListenerProperties::kBlocking ||
+ properties == EventListenerProperties::kBlockingAndPassive)) {
+ if (root_layer())
+ root_layer()->SetSubtreePropertyChanged();
+ SetNeedsFullTreeSync();
+ }
+
event_listener_properties_[index] = properties;
SetNeedsCommit();
}
@@ -1137,6 +1154,13 @@ void LayerTreeHost::SetPageScaleFactorAndLimits(float page_scale_factor,
return;
DCHECK_GE(page_scale_factor, min_page_scale_factor);
DCHECK_LE(page_scale_factor, max_page_scale_factor);
+ // We should never process non-unit page_scale_delta for an OOPIF subframe.
+ // TODO(wjmaclean): Remove this check as a pre-condition to closing the bug.
+ // https://crbug.com/845097
+ CHECK(!settings_.is_layer_tree_for_subframe ||
+ page_scale_factor == page_scale_factor_)
+ << "Setting PSF in oopif subframe: old psf = " << page_scale_factor_
+ << ", new psf = " << page_scale_factor;
page_scale_factor_ = page_scale_factor;
min_page_scale_factor_ = min_page_scale_factor;
@@ -1176,22 +1200,35 @@ void LayerTreeHost::SetRasterColorSpace(
}
void LayerTreeHost::SetContentSourceId(uint32_t id) {
- if (content_source_id_ == id)
- return;
content_source_id_ = id;
- SetNeedsCommit();
}
void LayerTreeHost::SetLocalSurfaceIdFromParent(
const viz::LocalSurfaceId& local_surface_id_from_parent) {
- if (local_surface_id_from_parent_ == local_surface_id_from_parent)
+ if (local_surface_id_from_parent_.parent_sequence_number() ==
+ local_surface_id_from_parent.parent_sequence_number() &&
+ local_surface_id_from_parent_.embed_token() ==
+ local_surface_id_from_parent.embed_token()) {
return;
+ }
+
+ TRACE_EVENT_WITH_FLOW2(
+ TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
+ "LocalSurfaceId.Submission.Flow",
+ TRACE_ID_GLOBAL(local_surface_id_from_parent.submission_trace_id()),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
+ "SetLocalSurfaceIdFromParent", "local_surface_id",
+ local_surface_id_from_parent.ToString());
local_surface_id_from_parent_ = local_surface_id_from_parent;
has_pushed_local_surface_id_from_parent_ = false;
UpdateDeferCommitsInternal();
SetNeedsCommit();
}
+void LayerTreeHost::ClearCachesOnNextCommit() {
+ clear_caches_on_next_commit_ = true;
+}
+
void LayerTreeHost::RequestNewLocalSurfaceId() {
// If surface synchronization is enabled, then we can still request a new
// viz::LocalSurfaceId but that request will be deferred until we have a valid
@@ -1236,10 +1273,6 @@ Layer* LayerTreeHost::LayerById(int id) const {
return iter != layer_id_map_.end() ? iter->second : nullptr;
}
-size_t LayerTreeHost::NumLayers() const {
- return layer_id_map_.size();
-}
-
bool LayerTreeHost::PaintContent(const LayerList& update_layer_list,
bool* content_has_slow_paths,
bool* content_has_non_aa_paint) {
@@ -1253,27 +1286,27 @@ bool LayerTreeHost::PaintContent(const LayerList& update_layer_list,
return did_paint_content;
}
-void LayerTreeHost::AddSurfaceLayerId(const viz::SurfaceId& surface_id) {
- if (++surface_layer_ids_[surface_id] == 1)
- needs_surface_ids_sync_ = true;
+void LayerTreeHost::AddSurfaceRange(const viz::SurfaceRange& surface_range) {
+ if (++surface_ranges_[surface_range] == 1)
+ needs_surface_ranges_sync_ = true;
}
-void LayerTreeHost::RemoveSurfaceLayerId(const viz::SurfaceId& surface_id) {
- auto iter = surface_layer_ids_.find(surface_id);
- if (iter == surface_layer_ids_.end())
+void LayerTreeHost::RemoveSurfaceRange(const viz::SurfaceRange& surface_range) {
+ auto iter = surface_ranges_.find(surface_range);
+ if (iter == surface_ranges_.end())
return;
if (--iter->second <= 0) {
- surface_layer_ids_.erase(iter);
- needs_surface_ids_sync_ = true;
+ surface_ranges_.erase(iter);
+ needs_surface_ranges_sync_ = true;
}
}
-base::flat_set<viz::SurfaceId> LayerTreeHost::SurfaceLayerIds() const {
- base::flat_set<viz::SurfaceId> ids;
- for (auto& map_entry : surface_layer_ids_)
- ids.insert(map_entry.first);
- return ids;
+base::flat_set<viz::SurfaceRange> LayerTreeHost::SurfaceRanges() const {
+ base::flat_set<viz::SurfaceRange> ranges;
+ for (auto& map_entry : surface_ranges_)
+ ranges.insert(map_entry.first);
+ return ranges;
}
void LayerTreeHost::AddLayerShouldPushProperties(Layer* layer) {
@@ -1295,6 +1328,13 @@ bool LayerTreeHost::LayerNeedsPushPropertiesForTesting(Layer* layer) const {
void LayerTreeHost::SetPageScaleFromImplSide(float page_scale) {
DCHECK(CommitRequested());
+ // We should never process non-unit page_scale_delta for an OOPIF subframe.
+ // TODO(wjmaclean): Remove this check as a pre-condition to closing the bug.
+ // https://crbug.com/845097
+ DCHECK(!settings_.is_layer_tree_for_subframe ||
+ page_scale == page_scale_factor_)
+ << "Setting PSF in oopif subframe: old psf = " << page_scale_factor_
+ << ", new psf = " << page_scale;
page_scale_factor_ = page_scale;
SetPropertyTreesNeedRebuild();
}
@@ -1353,7 +1393,7 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) {
EventListenerClass::kTouchEndOrCancel,
event_listener_properties(EventListenerClass::kTouchEndOrCancel));
- if (viewport_layers_.page_scale && viewport_layers_.inner_viewport_scroll) {
+ if (viewport_layers_.inner_viewport_scroll) {
LayerTreeImpl::ViewportLayerIds ids;
if (viewport_layers_.overscroll_elasticity)
ids.overscroll_elasticity = viewport_layers_.overscroll_elasticity->id();
@@ -1411,12 +1451,12 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) {
tree_impl->set_has_ever_been_drawn(false);
}
-void LayerTreeHost::PushSurfaceIdsTo(LayerTreeImpl* tree_impl) {
- if (needs_surface_ids_sync()) {
- tree_impl->ClearSurfaceLayerIds();
- tree_impl->SetSurfaceLayerIds(SurfaceLayerIds());
+void LayerTreeHost::PushSurfaceRangesTo(LayerTreeImpl* tree_impl) {
+ if (needs_surface_ranges_sync()) {
+ tree_impl->ClearSurfaceRanges();
+ tree_impl->SetSurfaceRanges(SurfaceRanges());
// Reset for next update
- set_needs_surface_ids_sync(false);
+ set_needs_surface_ranges_sync(false);
}
}
@@ -1536,7 +1576,9 @@ void LayerTreeHost::SetElementTransformMutated(
DCHECK(layer);
layer->OnTransformAnimated(transform);
- if (TransformNode* node = layer->GetTransformNode()) {
+ if (layer->has_transform_node()) {
+ TransformNode* node =
+ property_trees_.transform_tree.Node(layer->transform_tree_index());
if (node->local == transform)
return;
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index 2fbf3e6c021..8cea9a0da23 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -48,6 +48,10 @@
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/rect.h"
+namespace gfx {
+struct PresentationFeedback;
+}
+
namespace cc {
class HeadsUpDisplayLayer;
class Layer;
@@ -167,6 +171,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// synchronization.
virtual void SetNeedsCommit();
+ // Returns true after SetNeedsAnimate(), SetNeedsUpdateLayers() or
+ // SetNeedsCommit(), until it is satisfied.
+ bool RequestedMainFramePending();
+
// Requests that the next frame re-chooses crisp raster scales for all layers.
void SetNeedsRecalculateRasterScales();
@@ -177,6 +185,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// Enables/disables the compositor from requesting main frame updates from the
// client.
void SetDeferCommits(bool defer_commits);
+ // Returns the value last passed to SetDeferCommits(), though commits may be
+ // deferred also when the local_surface_id_from_parent() is not valid.
+ bool defer_commits() const { return defer_commits_; }
// Synchronously performs a main frame update and layer updates. Used only in
// single threaded mode when the compositor's internal scheduling is disabled.
@@ -212,10 +223,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// the compositor thread.
const base::WeakPtr<InputHandler>& GetInputHandler() const;
- // Informs the compositor that an active fling gesture being processed on the
- // main thread has been finished.
- void DidStopFlinging();
-
// Debugging and benchmarks ---------------------------------
void SetDebugState(const LayerTreeDebugState& debug_state);
const LayerTreeDebugState& GetDebugState() const;
@@ -242,7 +249,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// to the screen (it's entirely possible some frames may be dropped between
// the time this is called and the callback is run).
using PresentationTimeCallback =
- base::OnceCallback<void(base::TimeTicks, base::TimeDelta, uint32_t)>;
+ base::OnceCallback<void(const gfx::PresentationFeedback&)>;
void RequestPresentationTimeForNextFrame(PresentationTimeCallback callback);
void SetRootLayer(scoped_refptr<Layer> root_layer);
@@ -336,6 +343,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
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();
+
// If this LayerTreeHost needs a valid viz::LocalSurfaceId then commits will
// be deferred until a valid viz::LocalSurfaceId is provided.
void SetLocalSurfaceIdFromParent(
@@ -371,8 +382,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
void UnregisterLayer(Layer* layer);
Layer* LayerById(int id) const;
- size_t NumLayers() const;
-
bool in_update_property_trees() const { return in_update_property_trees_; }
bool PaintContent(const LayerList& update_layer_list,
bool* content_has_slow_paths,
@@ -382,9 +391,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
void SetHasCopyRequest(bool has_copy_request);
bool has_copy_request() const { return has_copy_request_; }
- void AddSurfaceLayerId(const viz::SurfaceId& surface_id);
- void RemoveSurfaceLayerId(const viz::SurfaceId& surface_id);
- base::flat_set<viz::SurfaceId> SurfaceLayerIds() const;
+ void AddSurfaceRange(const viz::SurfaceRange& surface_range);
+ void RemoveSurfaceRange(const viz::SurfaceRange& surface_range);
+ base::flat_set<viz::SurfaceRange> SurfaceRanges() const;
void AddLayerShouldPushProperties(Layer* layer);
void RemoveLayerShouldPushProperties(Layer* layer);
@@ -401,16 +410,16 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
virtual void SetNeedsFullTreeSync();
bool needs_full_tree_sync() const { return needs_full_tree_sync_; }
- bool needs_surface_ids_sync() const { return needs_surface_ids_sync_; }
- void set_needs_surface_ids_sync(bool needs_surface_ids_sync) {
- needs_surface_ids_sync_ = needs_surface_ids_sync;
+ bool needs_surface_ranges_sync() const { return needs_surface_ranges_sync_; }
+ void set_needs_surface_ranges_sync(bool needs_surface_ranges_sync) {
+ needs_surface_ranges_sync_ = needs_surface_ranges_sync;
}
void SetPropertyTreesNeedRebuild();
void PushPropertyTreesTo(LayerTreeImpl* tree_impl);
void PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl);
- void PushSurfaceIdsTo(LayerTreeImpl* tree_impl);
+ void PushSurfaceRangesTo(LayerTreeImpl* tree_impl);
void PushLayerTreeHostPropertiesTo(LayerTreeHostImpl* host_impl);
MutatorHost* mutator_host() const { return mutator_host_; }
@@ -454,10 +463,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
client_->DidReceiveCompositorFrameAck();
}
bool UpdateLayers();
- void DidPresentCompositorFrame(const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags);
+ void DidPresentCompositorFrame(
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback);
// Called when the compositor completed page scale animation.
void DidCompletePageScaleAnimation();
void ApplyScrollAndScale(ScrollAndScaleSet* info);
@@ -647,6 +656,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
int raster_color_space_id_ = -1;
gfx::ColorSpace raster_color_space_;
+ bool clear_caches_on_next_commit_ = false;
uint32_t content_source_id_;
viz::LocalSurfaceId local_surface_id_from_parent_;
// Used to detect surface invariant violations.
@@ -663,8 +673,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
gfx::Rect viewport_visible_rect_;
bool have_scroll_event_handlers_ = false;
- EventListenerProperties event_listener_properties_[static_cast<size_t>(
- EventListenerClass::kNumClasses)];
+ EventListenerProperties event_listener_properties_
+ [static_cast<size_t>(EventListenerClass::kLast) + 1];
std::unique_ptr<PendingPageScaleAnimation> pending_page_scale_animation_;
@@ -672,14 +682,15 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
bool needs_full_tree_sync_ = true;
- bool needs_surface_ids_sync_ = false;
+ bool needs_surface_ranges_sync_ = false;
gfx::Vector2dF elastic_overscroll_;
scoped_refptr<HeadsUpDisplayLayer> hud_layer_;
- // The number of SurfaceLayers that have fallback set to viz::SurfaceId.
- base::flat_map<viz::SurfaceId, int> surface_layer_ids_;
+ // The number of SurfaceRanges that have (fallback,primary) set to
+ // viz::SurfaceRange.
+ base::flat_map<viz::SurfaceRange, int> surface_ranges_;
// Set of layers that need to push properties.
std::unordered_set<Layer*> layers_that_should_push_properties_;
@@ -708,11 +719,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// added here.
std::vector<PresentationTimeCallback> pending_presentation_time_callbacks_;
- // Maps from the source frame presentation callbacks are requested for to
- // the callbacks.
- std::map<int, std::vector<PresentationTimeCallback>>
- frame_to_presentation_time_callbacks_;
-
DISALLOW_COPY_AND_ASSIGN(LayerTreeHost);
};
diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h
index 9cfdfcd7ff2..1c2e7fff509 100644
--- a/chromium/cc/trees/layer_tree_host_client.h
+++ b/chromium/cc/trees/layer_tree_host_client.h
@@ -11,6 +11,7 @@
#include "base/time/time.h"
namespace gfx {
+struct PresentationFeedback;
class Vector2dF;
}
@@ -89,10 +90,9 @@ class LayerTreeHostClient {
virtual void DidCommitAndDrawFrame() = 0;
virtual void DidReceiveCompositorFrameAck() = 0;
virtual void DidCompletePageScaleAnimation() = 0;
- // The only time a subframe ever gets its own LayerTree is when the subframe
- // renders in a different process its ancestors; this returns true in
- // that case.
- virtual bool IsForSubframe() = 0;
+ virtual void DidPresentCompositorFrame(
+ uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback) = 0;
protected:
virtual ~LayerTreeHostClient() {}
diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc
index 215b52f341d..d556360f899 100644
--- a/chromium/cc/trees/layer_tree_host_common.cc
+++ b/chromium/cc/trees/layer_tree_host_common.cc
@@ -36,7 +36,8 @@ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting::
float page_scale_factor,
const Layer* page_scale_layer,
const Layer* inner_viewport_scroll_layer,
- const Layer* outer_viewport_scroll_layer)
+ const Layer* outer_viewport_scroll_layer,
+ TransformNode* page_scale_transform_node)
: root_layer(root_layer),
device_viewport_size(device_viewport_size),
device_transform(device_transform),
@@ -44,7 +45,8 @@ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting::
page_scale_factor(page_scale_factor),
page_scale_layer(page_scale_layer),
inner_viewport_scroll_layer(inner_viewport_scroll_layer),
- outer_viewport_scroll_layer(outer_viewport_scroll_layer) {}
+ outer_viewport_scroll_layer(outer_viewport_scroll_layer),
+ page_scale_transform_node(page_scale_transform_node) {}
LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting::
CalcDrawPropsMainInputsForTesting(Layer* root_layer,
@@ -57,6 +59,7 @@ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting::
1.f,
nullptr,
nullptr,
+ nullptr,
nullptr) {}
LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting::
@@ -80,7 +83,8 @@ LayerTreeHostCommon::CalcDrawPropsImplInputs::CalcDrawPropsImplInputs(
int max_texture_size,
bool can_adjust_raster_scales,
RenderSurfaceList* render_surface_list,
- PropertyTrees* property_trees)
+ PropertyTrees* property_trees,
+ TransformNode* page_scale_transform_node)
: root_layer(root_layer),
device_viewport_size(device_viewport_size),
device_transform(device_transform),
@@ -95,7 +99,8 @@ LayerTreeHostCommon::CalcDrawPropsImplInputs::CalcDrawPropsImplInputs(
max_texture_size(max_texture_size),
can_adjust_raster_scales(can_adjust_raster_scales),
render_surface_list(render_surface_list),
- property_trees(property_trees) {}
+ property_trees(property_trees),
+ page_scale_transform_node(page_scale_transform_node) {}
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
@@ -116,7 +121,8 @@ LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
std::numeric_limits<int>::max() / 2,
false,
render_surface_list,
- GetPropertyTrees(root_layer)) {
+ GetPropertyTrees(root_layer),
+ nullptr) {
DCHECK(root_layer);
DCHECK(render_surface_list);
}
@@ -541,10 +547,43 @@ void CalculateDrawPropertiesInternal(
// on the active tree immediately affect the pending tree, so instead of
// trying to update property trees whenever these values change, we
// update property trees before using them.
+
+ // When the page scale layer is also the root layer, the node should also
+ // store the combined scale factor and not just the page scale factor.
+ // TODO(bokan): Need to implement this behavior for
+ // BlinkGeneratedPropertyTrees. i.e. (no page scale layer). Ideally by
+ // not baking these into the page scale layer.
+ bool combine_dsf_and_psf = inputs->page_scale_layer == inputs->root_layer;
+ float device_scale_factor_for_page_scale_node = 1.f;
+ gfx::Transform device_transform_for_page_scale_node;
+ if (combine_dsf_and_psf) {
+ DCHECK(
+ !inputs->root_layer->layer_tree_impl()->settings().use_layer_lists);
+ device_transform_for_page_scale_node = inputs->device_transform;
+ device_scale_factor_for_page_scale_node = inputs->device_scale_factor;
+ }
+
+ // We should never be setting a non-unit page scale factor on an oopif
+ // subframe ... if we attempt this log it and fail.
+ // TODO(wjmaclean): Remove as part of conditions for closing the bug.
+ // https://crbug.com/845097
+ if (inputs->page_scale_factor !=
+ inputs->property_trees->transform_tree.page_scale_factor() &&
+ !inputs->page_scale_transform_node) {
+ LOG(ERROR) << "Setting PageScale on subframe: new psf = "
+ << inputs->page_scale_factor << ", old psf = "
+ << inputs->property_trees->transform_tree.page_scale_factor()
+ << ", in_oopif = "
+ << inputs->root_layer->layer_tree_impl()
+ ->settings()
+ .is_layer_tree_for_subframe;
+ CHECK(false);
+ }
+
draw_property_utils::UpdatePageScaleFactor(
- inputs->property_trees, inputs->page_scale_layer,
- inputs->page_scale_factor, inputs->device_scale_factor,
- inputs->device_transform);
+ inputs->property_trees, inputs->page_scale_transform_node,
+ inputs->page_scale_factor, device_scale_factor_for_page_scale_node,
+ device_transform_for_page_scale_node);
draw_property_utils::UpdateElasticOverscroll(
inputs->property_trees, inputs->elastic_overscroll_application_layer,
inputs->elastic_overscroll);
@@ -554,9 +593,7 @@ void CalculateDrawPropertiesInternal(
property_trees->clip_tree.SetViewportClip(
gfx::RectF(gfx::SizeF(inputs->device_viewport_size)));
float page_scale_factor_for_root =
- inputs->page_scale_layer == inputs->root_layer
- ? inputs->page_scale_factor
- : 1.f;
+ combine_dsf_and_psf ? inputs->page_scale_factor : 1.f;
property_trees->transform_tree.SetRootTransformsAndScales(
inputs->device_scale_factor, page_scale_factor_for_root,
inputs->device_transform, inputs->root_layer->position());
diff --git a/chromium/cc/trees/layer_tree_host_common.h b/chromium/cc/trees/layer_tree_host_common.h
index 56799bf54ce..adbc352d802 100644
--- a/chromium/cc/trees/layer_tree_host_common.h
+++ b/chromium/cc/trees/layer_tree_host_common.h
@@ -17,6 +17,7 @@
#include "cc/layers/layer.h"
#include "cc/layers/layer_collections.h"
#include "cc/layers/layer_impl.h"
+#include "cc/layers/picture_layer.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/property_tree.h"
@@ -42,7 +43,8 @@ class CC_EXPORT LayerTreeHostCommon {
float page_scale_factor,
const Layer* page_scale_layer,
const Layer* inner_viewport_scroll_layer,
- const Layer* outer_viewport_scroll_layer);
+ const Layer* outer_viewport_scroll_layer,
+ TransformNode* page_scale_transform_node);
CalcDrawPropsMainInputsForTesting(Layer* root_layer,
const gfx::Size& device_viewport_size,
const gfx::Transform& device_transform);
@@ -56,6 +58,7 @@ class CC_EXPORT LayerTreeHostCommon {
const Layer* page_scale_layer;
const Layer* inner_viewport_scroll_layer;
const Layer* outer_viewport_scroll_layer;
+ TransformNode* page_scale_transform_node;
};
struct CC_EXPORT CalcDrawPropsImplInputs {
@@ -74,7 +77,8 @@ class CC_EXPORT LayerTreeHostCommon {
int max_texture_size,
bool can_adjust_raster_scales,
RenderSurfaceList* render_surface_list,
- PropertyTrees* property_trees);
+ PropertyTrees* property_trees,
+ TransformNode* page_scale_transform_node);
LayerImpl* root_layer;
gfx::Size device_viewport_size;
@@ -90,6 +94,7 @@ class CC_EXPORT LayerTreeHostCommon {
bool can_adjust_raster_scales;
RenderSurfaceList* render_surface_list;
PropertyTrees* property_trees;
+ TransformNode* page_scale_transform_node;
};
struct CC_EXPORT CalcDrawPropsImplInputsForTesting
@@ -181,7 +186,7 @@ void LayerTreeHostCommon::CallFunctionForEveryLayer(LayerTreeHost* host,
const Function& function) {
for (auto* layer : *host) {
function(layer);
- if (Layer* mask_layer = layer->mask_layer())
+ if (PictureLayer* mask_layer = layer->mask_layer())
function(mask_layer);
}
}
diff --git a/chromium/cc/trees/layer_tree_host_common_perftest.cc b/chromium/cc/trees/layer_tree_host_common_perftest.cc
index e599a6b4c1d..ab5d5e600da 100644
--- a/chromium/cc/trees/layer_tree_host_common_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_perftest.cc
@@ -21,6 +21,7 @@
#include "cc/test/layer_tree_test.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/transform_node.h"
#include "components/viz/test/paths.h"
#include "testing/perf/perf_test.h"
@@ -111,7 +112,10 @@ class CalcDrawPropsTest : public LayerTreeHostCommonPerfTest {
active_tree->elastic_overscroll()->Current(active_tree->IsActiveTree()),
active_tree->OverscrollElasticityLayer(), max_texture_size,
host_impl->settings().layer_transforms_should_scale_layer_contents,
- &update_list, active_tree->property_trees());
+ &update_list, active_tree->property_trees(),
+ active_tree->property_trees()->transform_tree.Node(
+ active_tree->InnerViewportContainerLayer()
+ ->transform_tree_index()));
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
}
};
diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc
index 329e9cd4b7e..f63d1a24987 100644
--- a/chromium/cc/trees/layer_tree_host_common_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc
@@ -56,6 +56,13 @@
namespace cc {
namespace {
+bool LayerSubtreeHasCopyRequest(Layer* layer) {
+ LayerTreeHost* host = layer->layer_tree_host();
+ int index = layer->effect_tree_index();
+ auto* node = host->property_trees()->effect_tree.Node(index);
+ return node->subtree_has_copy_request;
+}
+
class VerifyTreeCalcsLayerTreeSettings : public LayerTreeSettings {
public:
VerifyTreeCalcsLayerTreeSettings() = default;
@@ -115,6 +122,12 @@ 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;
+ if (page_scale_layer) {
+ PropertyTrees* property_trees =
+ root_layer->layer_tree_host()->property_trees();
+ inputs.page_scale_transform_node = property_trees->transform_tree.Node(
+ page_scale_layer->transform_tree_index());
+ }
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
}
@@ -149,6 +162,12 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
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();
+ inputs.page_scale_transform_node = property_trees->transform_tree.Node(
+ page_scale_layer->transform_tree_index());
+ }
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
}
@@ -298,16 +317,6 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
class LayerTreeHostCommonTest : public LayerTreeHostCommonTestBase,
public testing::Test {};
-class LayerWithForcedDrawsContent : public Layer {
- public:
- LayerWithForcedDrawsContent() = default;
-
- bool DrawsContent() const override { return true; }
-
- private:
- ~LayerWithForcedDrawsContent() override = default;
-};
-
class LayerTreeSettingsScaleContent : public VerifyTreeCalcsLayerTreeSettings {
public:
LayerTreeSettingsScaleContent() {
@@ -1251,6 +1260,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
root, root->bounds(), translate, &render_surface_list_impl);
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_layer = root;
+ inputs.page_scale_transform_node =
+ inputs.property_trees->transform_tree.Node(
+ inputs.page_scale_layer->transform_tree_index());
inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
gfx::Transform page_scaled_translate = translate;
@@ -2166,12 +2178,14 @@ TEST_F(LayerTreeHostCommonTest, LargeTransforms) {
}
static bool TransformIsAnimating(LayerImpl* layer) {
- return layer->GetMutatorHost()->IsAnimatingTransformProperty(
+ MutatorHost* host = layer->layer_tree_impl()->mutator_host();
+ return host->IsAnimatingTransformProperty(
layer->element_id(), layer->GetElementTypeForAnimation());
}
static bool HasPotentiallyRunningTransformAnimation(LayerImpl* layer) {
- return layer->GetMutatorHost()->HasPotentiallyRunningTransformAnimation(
+ MutatorHost* host = layer->layer_tree_impl()->mutator_host();
+ return host->HasPotentiallyRunningTransformAnimation(
layer->element_id(), layer->GetElementTypeForAnimation());
}
@@ -3046,7 +3060,7 @@ TEST_F(LayerTreeHostCommonTest, OcclusionBySiblingOfTarget) {
root->test_properties()->AddChild(std::move(child));
host_impl.active_tree()->SetRootLayerForTesting(std::move(root));
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl.active_tree()->UpdateDrawProperties();
@@ -3092,7 +3106,7 @@ TEST_F(LayerTreeHostCommonTest, TextureLayerSnapping) {
root->test_properties()->AddChild(std::move(child));
host_impl.active_tree()->SetRootLayerForTesting(std::move(root));
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl.active_tree()->UpdateDrawProperties();
@@ -3154,7 +3168,7 @@ TEST_F(LayerTreeHostCommonTest,
root->test_properties()->AddChild(std::move(occluding_child));
host_impl.active_tree()->SetRootLayerForTesting(std::move(root));
host_impl.SetVisible(true);
- host_impl.InitializeRenderer(layer_tree_frame_sink.get());
+ host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl.active_tree()->UpdateDrawProperties();
@@ -4364,7 +4378,8 @@ TEST_F(LayerTreeHostCommonTest, LayerSearch) {
scoped_refptr<Layer> root = Layer::Create();
scoped_refptr<Layer> child = Layer::Create();
scoped_refptr<Layer> grand_child = Layer::Create();
- scoped_refptr<Layer> mask_layer = Layer::Create();
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> mask_layer = PictureLayer::Create(&client);
child->AddChild(grand_child.get());
child->SetMaskLayer(mask_layer.get());
@@ -7425,9 +7440,12 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) {
EXPECT_EQ(0.f, GetStartingAnimationScale(child_raw));
EXPECT_EQ(0.f, GetStartingAnimationScale(grand_child_raw));
- grand_parent_animation->AbortKeyframeModels(TargetProperty::TRANSFORM, false);
- parent_animation->AbortKeyframeModels(TargetProperty::TRANSFORM, false);
- child_animation->AbortKeyframeModels(TargetProperty::TRANSFORM, false);
+ grand_parent_animation->AbortKeyframeModelsWithProperty(
+ TargetProperty::TRANSFORM, false);
+ parent_animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM,
+ false);
+ child_animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM,
+ false);
TransformOperations perspective;
perspective.AppendPerspective(10.f);
@@ -7449,7 +7467,8 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) {
EXPECT_EQ(0.f, GetStartingAnimationScale(child_raw));
EXPECT_EQ(0.f, GetStartingAnimationScale(grand_child_raw));
- child_animation->AbortKeyframeModels(TargetProperty::TRANSFORM, false);
+ child_animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM,
+ false);
gfx::Transform scale_matrix;
scale_matrix.Scale(1.f, 2.f);
@@ -7844,6 +7863,8 @@ TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
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());
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
EXPECT_FLOAT_EQ(3.f, root_layer->GetIdealContentsScale());
@@ -8299,8 +8320,9 @@ TEST_F(LayerTreeHostCommonTest, AnimatedOpacityCreatesRenderSurface) {
}
static bool FilterIsAnimating(LayerImpl* layer) {
- return layer->GetMutatorHost()->IsAnimatingFilterProperty(
- layer->element_id(), layer->GetElementTypeForAnimation());
+ MutatorHost* host = layer->layer_tree_impl()->mutator_host();
+ return host->IsAnimatingFilterProperty(layer->element_id(),
+ layer->GetElementTypeForAnimation());
}
// Verify that having an animated filter (but no current filter, as these
@@ -8332,7 +8354,8 @@ TEST_F(LayerTreeHostCommonTest, AnimatedFilterCreatesRenderSurface) {
}
bool HasPotentiallyRunningFilterAnimation(const LayerImpl& layer) {
- return layer.GetMutatorHost()->HasPotentiallyRunningFilterAnimation(
+ MutatorHost* host = layer.layer_tree_impl()->mutator_host();
+ return host->HasPotentiallyRunningFilterAnimation(
layer.element_id(), layer.GetElementTypeForAnimation());
}
@@ -8599,21 +8622,22 @@ TEST_F(LayerTreeHostCommonTest, HasCopyRequestsInTargetSubtree) {
child2->SetOpacity(0.f);
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root.get());
- EXPECT_TRUE(root->has_copy_requests_in_target_subtree());
- EXPECT_TRUE(child1->has_copy_requests_in_target_subtree());
- EXPECT_FALSE(child2->has_copy_requests_in_target_subtree());
- EXPECT_TRUE(grandchild->has_copy_requests_in_target_subtree());
- EXPECT_TRUE(greatgrandchild->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(LayerSubtreeHasCopyRequest(root.get()));
+ EXPECT_TRUE(LayerSubtreeHasCopyRequest(child1.get()));
+ EXPECT_FALSE(LayerSubtreeHasCopyRequest(child2.get()));
+ EXPECT_TRUE(LayerSubtreeHasCopyRequest(grandchild.get()));
+ EXPECT_TRUE(LayerSubtreeHasCopyRequest(greatgrandchild.get()));
}
TEST_F(LayerTreeHostCommonTest, SkippingSubtreeMain) {
- scoped_refptr<Layer> root = Layer::Create();
FakeContentLayerClient client;
+
+ scoped_refptr<Layer> root = Layer::Create();
client.set_bounds(root->bounds());
- scoped_refptr<LayerWithForcedDrawsContent> child =
- base::MakeRefCounted<LayerWithForcedDrawsContent>();
- scoped_refptr<LayerWithForcedDrawsContent> grandchild =
- base::MakeRefCounted<LayerWithForcedDrawsContent>();
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetIsDrawable(true);
+ scoped_refptr<Layer> grandchild = Layer::Create();
+ grandchild->SetIsDrawable(true);
scoped_refptr<FakePictureLayer> greatgrandchild(
FakePictureLayer::Create(&client));
@@ -9025,10 +9049,10 @@ TEST_F(LayerTreeHostCommonTest, LayerTreeRebuildTest) {
child->RequestCopyOfOutput(viz::CopyOutputRequest::CreateStubForTesting());
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root.get());
- EXPECT_TRUE(root->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(LayerSubtreeHasCopyRequest(root.get()));
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root.get());
- EXPECT_TRUE(root->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(LayerSubtreeHasCopyRequest(root.get()));
}
TEST_F(LayerTreeHostCommonTest, ResetPropertyTreeIndices) {
@@ -9727,8 +9751,8 @@ TEST_F(LayerTreeHostCommonTest, LargeTransformTest) {
TEST_F(LayerTreeHostCommonTest, PropertyTreesRebuildWithOpacityChanges) {
scoped_refptr<Layer> root = Layer::Create();
- scoped_refptr<LayerWithForcedDrawsContent> child =
- base::MakeRefCounted<LayerWithForcedDrawsContent>();
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetIsDrawable(true);
root->AddChild(child);
host()->SetRootLayer(root);
@@ -9769,8 +9793,8 @@ TEST_F(LayerTreeHostCommonTest, PropertyTreesRebuildWithOpacityChanges) {
TEST_F(LayerTreeHostCommonTest, OpacityAnimationsTrackingTest) {
scoped_refptr<Layer> root = Layer::Create();
- scoped_refptr<LayerWithForcedDrawsContent> animated =
- base::MakeRefCounted<LayerWithForcedDrawsContent>();
+ scoped_refptr<Layer> animated = Layer::Create();
+ animated->SetIsDrawable(true);
root->AddChild(animated);
host()->SetRootLayer(root);
host()->SetElementIdsForTesting();
@@ -9810,8 +9834,8 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimationsTrackingTest) {
EXPECT_TRUE(node->is_currently_animating_opacity);
EXPECT_TRUE(node->has_potential_opacity_animation);
- animation->AbortKeyframeModels(TargetProperty::OPACITY,
- false /*needs_completion*/);
+ animation->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY,
+ false /*needs_completion*/);
node = tree.Node(animated->effect_tree_index());
EXPECT_FALSE(node->is_currently_animating_opacity);
EXPECT_FALSE(node->has_potential_opacity_animation);
@@ -9819,8 +9843,8 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimationsTrackingTest) {
TEST_F(LayerTreeHostCommonTest, TransformAnimationsTrackingTest) {
scoped_refptr<Layer> root = Layer::Create();
- scoped_refptr<LayerWithForcedDrawsContent> animated =
- base::MakeRefCounted<LayerWithForcedDrawsContent>();
+ scoped_refptr<Layer> animated = Layer::Create();
+ animated->SetIsDrawable(true);
root->AddChild(animated);
host()->SetRootLayer(root);
host()->SetElementIdsForTesting();
@@ -9869,8 +9893,8 @@ TEST_F(LayerTreeHostCommonTest, TransformAnimationsTrackingTest) {
EXPECT_TRUE(node->is_currently_animating);
EXPECT_TRUE(node->has_potential_animation);
- animation->AbortKeyframeModels(TargetProperty::TRANSFORM,
- false /*needs_completion*/);
+ animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM,
+ false /*needs_completion*/);
node = tree.Node(animated->transform_tree_index());
EXPECT_FALSE(node->is_currently_animating);
EXPECT_FALSE(node->has_potential_animation);
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index df0758ace5d..507ece40522 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -20,6 +20,7 @@
#include "base/containers/adapters.h"
#include "base/containers/flat_map.h"
#include "base/json/json_writer.h"
+#include "base/memory/memory_coordinator_client_registry.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
#include "base/numerics/safe_conversions.h"
@@ -27,6 +28,7 @@
#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
#include "base/trace_event/trace_event_argument.h"
+#include "build/build_config.h"
#include "cc/base/devtools_instrumentation.h"
#include "cc/base/histograms.h"
#include "cc/base/math_util.h"
@@ -68,7 +70,6 @@
#include "cc/trees/draw_property_utils.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/frame_rate_counter.h"
-#include "cc/trees/frame_token_allocator.h"
#include "cc/trees/image_animation_controller.h"
#include "cc/trees/latency_info_swap_promise_monitor.h"
#include "cc/trees/layer_tree_frame_sink.h"
@@ -107,6 +108,7 @@
#include "ui/gfx/geometry/scroll_offset.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/skia_util.h"
namespace cc {
@@ -163,9 +165,12 @@ viz::ResourceFormat TileRasterBufferFormat(
// it and resets to the same location.
class ViewportAnchor {
public:
- ViewportAnchor(LayerImpl* inner_scroll, LayerImpl* outer_scroll)
- : inner_(inner_scroll), outer_(outer_scroll) {
- viewport_in_content_coordinates_ = inner_->CurrentScrollOffset();
+ ViewportAnchor(ScrollNode* inner_scroll,
+ LayerImpl* outer_scroll,
+ LayerTreeImpl* tree_impl)
+ : inner_(inner_scroll), outer_(outer_scroll), tree_impl_(tree_impl) {
+ viewport_in_content_coordinates_ =
+ scroll_tree().current_scroll_offset(inner_->element_id);
if (outer_)
viewport_in_content_coordinates_ += outer_->CurrentScrollOffset();
@@ -174,22 +179,28 @@ class ViewportAnchor {
void ResetViewportToAnchoredPosition() {
DCHECK(outer_);
- inner_->ClampScrollToMaxScrollOffset();
+ scroll_tree().ClampScrollToMaxScrollOffset(inner_, tree_impl_);
outer_->ClampScrollToMaxScrollOffset();
gfx::ScrollOffset viewport_location =
- inner_->CurrentScrollOffset() + outer_->CurrentScrollOffset();
+ scroll_tree().current_scroll_offset(inner_->element_id) +
+ outer_->CurrentScrollOffset();
gfx::Vector2dF delta =
viewport_in_content_coordinates_.DeltaFrom(viewport_location);
- delta = inner_->ScrollBy(delta);
+ delta = scroll_tree().ScrollBy(inner_, delta, tree_impl_);
outer_->ScrollBy(delta);
}
private:
- LayerImpl* inner_;
+ ScrollTree& scroll_tree() {
+ return tree_impl_->property_trees()->scroll_tree;
+ }
+
+ ScrollNode* inner_;
LayerImpl* outer_;
+ LayerTreeImpl* tree_impl_;
gfx::ScrollOffset viewport_in_content_coordinates_;
};
@@ -221,6 +232,25 @@ void RecordCompositorSlowScrollMetric(InputHandler::ScrollInputType type,
}
}
+ui::FrameMetricsSettings LTHI_FrameMetricsSettings(
+ const LayerTreeSettings& settings) {
+ ui::FrameMetricsSource source =
+ settings.commit_to_active_tree
+ ? ui::FrameMetricsSource::UiCompositor
+ : ui::FrameMetricsSource::RendererCompositor;
+ ui::FrameMetricsSourceThread source_thread =
+ settings.commit_to_active_tree
+ ? ui::FrameMetricsSourceThread::UiCompositor
+ : ui::FrameMetricsSourceThread::RendererCompositor;
+ ui::FrameMetricsCompileTarget compile_target =
+ settings.using_synchronous_renderer_compositor
+ ? ui::FrameMetricsCompileTarget::SynchronousCompositor
+ : settings.wait_for_all_pipeline_stages_before_draw
+ ? ui::FrameMetricsCompileTarget::Headless
+ : ui::FrameMetricsCompileTarget::Chromium;
+ return ui::FrameMetricsSettings(source, source_thread, compile_target);
+}
+
} // namespace
DEFINE_SCOPED_UMA_HISTOGRAM_TIMER(PendingTreeDurationHistogramTimer,
@@ -264,23 +294,11 @@ LayerTreeHostImpl::LayerTreeHostImpl(
: client_(client),
task_runner_provider_(task_runner_provider),
current_begin_frame_tracker_(BEGINFRAMETRACKER_FROM_HERE),
- need_update_gpu_rasterization_status_(false),
- content_has_slow_paths_(false),
- content_has_non_aa_paint_(false),
- has_gpu_rasterization_trigger_(false),
- use_gpu_rasterization_(false),
- use_msaa_(false),
- gpu_rasterization_status_(GpuRasterizationStatus::OFF_DEVICE),
- input_handler_client_(nullptr),
- did_lock_scrolling_layer_(false),
- wheel_scrolling_(false),
- scroll_affects_scroll_handler_(false),
- tile_priorities_dirty_(false),
settings_(settings),
- visible_(false),
- cached_managed_memory_policy_(settings.memory_policy),
is_synchronous_single_threaded_(!task_runner_provider->HasImplThread() &&
- !settings.single_thread_proxy_scheduler),
+ !settings_.single_thread_proxy_scheduler),
+ resource_provider_(settings_.delegated_sync_points_required),
+ cached_managed_memory_policy_(settings.memory_policy),
// Must be initialized after is_synchronous_single_threaded_ and
// task_runner_provider_.
tile_manager_(this,
@@ -290,28 +308,17 @@ LayerTreeHostImpl::LayerTreeHostImpl(
? std::numeric_limits<size_t>::max()
: settings.scheduled_raster_task_limit,
settings.ToTileManagerSettings()),
- pinch_gesture_active_(false),
- pinch_gesture_end_should_clear_scrolling_node_(false),
fps_counter_(
FrameRateCounter::Create(task_runner_provider_->HasImplThread())),
memory_history_(MemoryHistory::Create()),
debug_rect_history_(DebugRectHistory::Create()),
- max_memory_needed_bytes_(0),
- resourceless_software_draw_(false),
mutator_host_(std::move(mutator_host)),
rendering_stats_instrumentation_(rendering_stats_instrumentation),
micro_benchmark_controller_(this),
task_graph_runner_(task_graph_runner),
id_(id),
- requires_high_res_to_draw_(false),
- is_likely_to_require_a_draw_(false),
- has_valid_layer_tree_frame_sink_(false),
consecutive_frame_with_damage_count_(settings.damaged_frame_limit),
scroll_animating_latched_element_id_(kInvalidElementId),
- has_scrolled_by_wheel_(false),
- has_scrolled_by_touch_(false),
- touchpad_and_wheel_scroll_latching_enabled_(false),
- impl_thread_phase_(ImplThreadPhase::IDLE),
// It is safe to use base::Unretained here since we will outlive the
// ImageAnimationController.
image_animation_controller_(
@@ -320,8 +327,9 @@ LayerTreeHostImpl::LayerTreeHostImpl(
&LayerTreeHostImpl::RequestInvalidationForAnimatedImages,
base::Unretained(this)),
settings_.enable_image_animation_resync),
- default_color_space_id_(gfx::ColorSpace::GetNextId()),
- default_color_space_(gfx::ColorSpace::CreateSRGB()) {
+ frame_metrics_(LTHI_FrameMetricsSettings(settings_)),
+ skipped_frame_tracker_(&frame_metrics_),
+ is_animating_for_snap_(false) {
DCHECK(mutator_host_);
mutator_host_->SetMutatorHostClient(this);
@@ -345,6 +353,7 @@ LayerTreeHostImpl::LayerTreeHostImpl(
this, settings.top_controls_show_threshold,
settings.top_controls_hide_threshold);
+ base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
memory_pressure_listener_.reset(
new base::MemoryPressureListener(base::BindRepeating(
&LayerTreeHostImpl::OnMemoryPressure, base::Unretained(this))));
@@ -356,13 +365,12 @@ LayerTreeHostImpl::~LayerTreeHostImpl() {
TRACE_EVENT_OBJECT_DELETED_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"cc::LayerTreeHostImpl", id_);
- // It is released before shutdown.
+ // The frame sink is released before shutdown, which takes down
+ // all the resource and raster structures.
DCHECK(!layer_tree_frame_sink_);
-
- DCHECK(!resource_provider_);
DCHECK(!resource_pool_);
- DCHECK(!single_thread_synchronous_task_graph_runner_);
DCHECK(!image_decode_cache_);
+ DCHECK(!single_thread_synchronous_task_graph_runner_);
if (input_handler_client_) {
input_handler_client_->WillShutdown();
@@ -371,7 +379,9 @@ LayerTreeHostImpl::~LayerTreeHostImpl() {
if (scroll_elasticity_helper_)
scroll_elasticity_helper_.reset();
- // The layer trees must be destroyed before the layer tree host.
+ // The layer trees must be destroyed before the LayerTreeHost. Also, if they
+ // are holding onto any resources, destroying them will release them, before
+ // we mark any leftover resources as lost.
if (recycle_tree_)
recycle_tree_->Shutdown();
if (pending_tree_)
@@ -381,6 +391,11 @@ LayerTreeHostImpl::~LayerTreeHostImpl() {
pending_tree_ = nullptr;
active_tree_ = nullptr;
+ base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
+
+ // All resources should already be removed, so lose anything still exported.
+ resource_provider_.ShutdownAndReleaseAllResources();
+
mutator_host_->ClearMutators();
mutator_host_->SetMutatorHostClient(nullptr);
}
@@ -617,7 +632,7 @@ void LayerTreeHostImpl::StartPageScaleAnimation(
bool anchor_point,
float page_scale,
base::TimeDelta duration) {
- if (!InnerViewportScrollLayer())
+ if (!InnerViewportScrollNode())
return;
gfx::ScrollOffset scroll_total = active_tree_->TotalScrollOffset();
@@ -770,6 +785,18 @@ LayerTreeHostImpl::EventListenerTypeForTouchStartOrMoveAt(
: InputHandler::TouchStartOrMoveEventListenerType::HANDLER;
}
+bool LayerTreeHostImpl::HasWheelEventHandlerAt(
+ const gfx::Point& viewport_point) const {
+ gfx::PointF device_viewport_point = gfx::ScalePoint(
+ gfx::PointF(viewport_point), active_tree_->device_scale_factor());
+
+ LayerImpl* layer_impl_with_wheel_event_handler =
+ active_tree_->FindLayerThatIsHitByPointInWheelEventHandlerRegion(
+ device_viewport_point);
+
+ return layer_impl_with_wheel_event_handler;
+}
+
std::unique_ptr<SwapPromiseMonitor>
LayerTreeHostImpl::CreateLatencyInfoSwapPromiseMonitor(
ui::LatencyInfo* latency) {
@@ -834,10 +861,10 @@ void LayerTreeHostImpl::FrameData::AsValueInto(
value->SetBoolean("has_no_damage", has_no_damage);
// Quad data can be quite large, so only dump render passes if we select
- // cc.debug.quads.
+ // viz.quads.
bool quads_enabled;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(
- TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"), &quads_enabled);
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("viz.quads"),
+ &quads_enabled);
if (quads_enabled) {
value->BeginArray("render_passes");
for (size_t i = 0; i < render_passes.size(); ++i) {
@@ -920,6 +947,18 @@ bool LayerTreeHostImpl::HasDamage() const {
if (!viewport_damage_rect_.IsEmpty())
return true;
+ // If the set of referenced surfaces has changed then we must submit a new
+ // CompositorFrame to update surface references.
+ if (last_draw_referenced_surfaces_ != active_tree()->SurfaceRanges())
+ return true;
+
+ // If we have a new LocalSurfaceId, we must always submit a CompositorFrame
+ // because the parent is blocking on us.
+ if (last_draw_local_surface_id_ !=
+ child_local_surface_id_allocator_.GetCurrentLocalSurfaceId()) {
+ return true;
+ }
+
const LayerTreeImpl* active_tree = active_tree_.get();
// If the root render surface has no visible damage, then don't generate a
@@ -929,18 +968,10 @@ bool LayerTreeHostImpl::HasDamage() const {
root_surface->GetDamageRect().Intersects(root_surface->content_rect());
bool hud_wants_to_draw_ = active_tree->hud_layer() &&
active_tree->hud_layer()->IsAnimatingHUDContents();
- bool must_always_swap =
- layer_tree_frame_sink_->capabilities().must_always_swap;
-
- // If we have a new LocalSurfaceId, we must always submit a CompositorFrame
- // because the parent is blocking on us.
- bool local_surface_id_changed =
- last_draw_local_surface_id_ !=
- child_local_surface_id_allocator_.GetCurrentLocalSurfaceId();
return root_surface_has_visible_damage ||
active_tree_->property_trees()->effect_tree.HasCopyRequests() ||
- must_always_swap || hud_wants_to_draw_ || local_surface_id_changed;
+ hud_wants_to_draw_;
}
DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
@@ -1064,13 +1095,9 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
render_surface->AppendQuads(draw_mode, target_render_pass,
&append_quads_data);
}
- } else if (it.state() == EffectTreeLayerListIterator::State::LAYER &&
- !it.current_layer()->visible_layer_rect().IsEmpty()) {
+ } else if (it.state() == EffectTreeLayerListIterator::State::LAYER) {
LayerImpl* layer = it.current_layer();
- bool occluded =
- layer->draw_properties().occlusion_in_content_space.IsOccluded(
- layer->visible_layer_rect());
- if (!occluded && layer->WillDraw(draw_mode, resource_provider_.get())) {
+ if (layer->WillDraw(draw_mode, &resource_provider_)) {
DCHECK_EQ(active_tree_.get(), layer->layer_tree_impl());
frame->will_draw_layers.push_back(layer);
@@ -1222,12 +1249,6 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
return draw_result;
}
-void LayerTreeHostImpl::MainThreadHasStoppedFlinging() {
- browser_controls_offset_manager_->MainThreadHasStoppedFlinging();
- if (input_handler_client_)
- input_handler_client_->MainThreadHasStoppedFlinging();
-}
-
void LayerTreeHostImpl::DidAnimateScrollOffset() {
client_->SetNeedsCommitOnImplThread();
client_->RenewTreePriority();
@@ -1239,8 +1260,12 @@ void LayerTreeHostImpl::SetViewportDamage(const gfx::Rect& damage_rect) {
void LayerTreeHostImpl::InvalidateContentOnImplSide() {
DCHECK(!pending_tree_);
- // Invalidation should never be ran outside the impl frame.
- DCHECK_EQ(impl_thread_phase_, ImplThreadPhase::INSIDE_IMPL_FRAME);
+ // Invalidation should never be ran outside the impl frame for non
+ // synchronous compositor mode. For devices that use synchronous compositor,
+ // e.g. Android Webview, the assertion is not guaranteed because it may ask
+ // for a frame at any time.
+ DCHECK(impl_thread_phase_ == ImplThreadPhase::INSIDE_IMPL_FRAME ||
+ settings_.using_synchronous_renderer_compositor);
if (!CommitToActiveTree())
CreatePendingTree();
@@ -1248,18 +1273,28 @@ void LayerTreeHostImpl::InvalidateContentOnImplSide() {
UpdateSyncTreeAfterCommitOrImplSideInvalidation();
}
-void LayerTreeHostImpl::InvalidateLayerTreeFrameSink() {
+void LayerTreeHostImpl::InvalidateLayerTreeFrameSink(bool needs_redraw) {
DCHECK(layer_tree_frame_sink());
- layer_tree_frame_sink()->Invalidate();
+
+ layer_tree_frame_sink()->Invalidate(needs_redraw);
+ skipped_frame_tracker_.DidProduceFrame();
}
DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
TRACE_EVENT1("cc", "LayerTreeHostImpl::PrepareToDraw", "SourceFrameNumber",
active_tree_->source_frame_number());
+ TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
+ TRACE_ID_GLOBAL(CurrentBeginFrameArgs().trace_id),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "step", "GenerateRenderPass");
if (input_handler_client_)
input_handler_client_->ReconcileElasticOverscrollAndRootScroll();
- if (const char* client_name = GetClientNameForMetrics()) {
+ // |client_name| is used for various UMA histograms below.
+ // GetClientNameForMetrics only returns one non-null value over the lifetime
+ // of the process, so the histogram names are runtime constant.
+ const char* client_name = GetClientNameForMetrics();
+ if (client_name) {
size_t total_memory_in_bytes = 0;
size_t total_gpu_memory_for_tilings_in_bytes = 0;
for (const PictureLayerImpl* layer : active_tree()->picture_layers()) {
@@ -1267,16 +1302,12 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
total_gpu_memory_for_tilings_in_bytes += layer->GPUMemoryUsageInBytes();
}
if (total_memory_in_bytes != 0) {
- // GetClientNameForMetrics only returns one non-null value over the
- // lifetime of the process, so this histogram name is runtime constant.
UMA_HISTOGRAM_COUNTS(
base::StringPrintf("Compositing.%s.PictureMemoryUsageKb",
client_name),
base::saturated_cast<int>(total_memory_in_bytes / 1024));
}
- // GetClientNameForMetrics only returns one non-null value over the lifetime
- // of the process, so these histogram names are runtime constant.
UMA_HISTOGRAM_CUSTOM_COUNTS(
base::StringPrintf("Compositing.%s.NumActiveLayers", client_name),
base::saturated_cast<int>(active_tree_->NumLayers()), 1, 400, 20);
@@ -1323,6 +1354,11 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
}
DrawResult draw_result = CalculateRenderPasses(frame);
+ if (client_name) {
+ UMA_HISTOGRAM_ENUMERATION(
+ base::StringPrintf("Compositing.%s.DrawResult", client_name),
+ draw_result);
+ }
if (draw_result != DRAW_SUCCESS) {
DCHECK(!resourceless_software_draw_);
return draw_result;
@@ -1729,40 +1765,45 @@ void LayerTreeHostImpl::DidReceiveCompositorFrameAck() {
client_->DidReceiveCompositorFrameAckOnImplThread();
}
-void LayerTreeHostImpl::DidPresentCompositorFrame(uint32_t presentation_token,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) {
- TRACE_EVENT_MARK_WITH_TIMESTAMP0("cc,benchmark", "FramePresented", time);
- std::vector<int> source_frames;
- auto iter = presentation_token_to_frame_.begin();
- for (; iter != presentation_token_to_frame_.end() &&
- iter->first <= presentation_token;
- ++iter) {
- source_frames.push_back(iter->second);
- }
- presentation_token_to_frame_.erase(presentation_token_to_frame_.begin(),
- iter);
- if (presentation_token_to_frame_.empty()) {
- DCHECK_EQ(last_presentation_token_, presentation_token);
- last_presentation_token_ = 0u;
- }
+LayerTreeHostImpl::FrameTokenInfo::FrameTokenInfo(
+ uint32_t token,
+ base::TimeTicks cc_frame_time,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks)
+ : token(token),
+ cc_frame_time(cc_frame_time),
+ callbacks(std::move(callbacks)) {}
+
+LayerTreeHostImpl::FrameTokenInfo::FrameTokenInfo(FrameTokenInfo&&) = default;
+LayerTreeHostImpl::FrameTokenInfo::~FrameTokenInfo() = default;
+
+void LayerTreeHostImpl::DidPresentCompositorFrame(
+ uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback) {
+ TRACE_EVENT_MARK_WITH_TIMESTAMP0("cc,benchmark", "FramePresented",
+ feedback.timestamp);
+ std::vector<LayerTreeHost::PresentationTimeCallback> all_callbacks;
+ while (!frame_token_infos_.empty()) {
+ auto info = frame_token_infos_.begin();
+ if (viz::FrameTokenGT(info->token, frame_token))
+ break;
- client_->DidPresentCompositorFrameOnImplThread(source_frames, time, refresh,
- flags);
-}
+ // Update compositor frame latency and smoothness stats only for frames
+ // that caused on-screen damage.
+ if (info->token == frame_token)
+ frame_metrics_.AddFrameDisplayed(info->cc_frame_time, feedback.timestamp);
-void LayerTreeHostImpl::DidDiscardCompositorFrame(uint32_t presentation_token) {
+ std::copy(std::make_move_iterator(info->callbacks.begin()),
+ std::make_move_iterator(info->callbacks.end()),
+ std::back_inserter(all_callbacks));
+ frame_token_infos_.erase(info);
+ }
+ client_->DidPresentCompositorFrameOnImplThread(
+ frame_token, std::move(all_callbacks), feedback);
}
void LayerTreeHostImpl::ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) {
- // TODO(piman): We may need to do some validation on this ack before
- // processing it.
- if (!resource_provider_)
- return;
-
- resource_provider_->ReceiveReturnsFromParent(resources);
+ resource_provider_.ReceiveReturnsFromParent(resources);
// In OOM, we now might be able to release more resources that were held
// because they were exported.
@@ -1792,8 +1833,15 @@ void LayerTreeHostImpl::ReclaimResources(
void LayerTreeHostImpl::OnDraw(const gfx::Transform& transform,
const gfx::Rect& viewport,
- bool resourceless_software_draw) {
+ bool resourceless_software_draw,
+ bool skip_draw) {
DCHECK(!resourceless_software_draw_);
+
+ if (skip_draw) {
+ client_->OnDrawForLayerTreeFrameSink(resourceless_software_draw_, true);
+ return;
+ }
+
const bool transform_changed = external_transform_ != transform;
const bool viewport_changed = external_viewport_ != viewport;
@@ -1817,7 +1865,8 @@ void LayerTreeHostImpl::OnDraw(const gfx::Transform& transform,
client_->OnCanDrawStateChanged(CanDraw());
}
- client_->OnDrawForLayerTreeFrameSink(resourceless_software_draw_);
+ client_->OnDrawForLayerTreeFrameSink(resourceless_software_draw_,
+ skip_draw);
}
if (resourceless_software_draw) {
@@ -1836,15 +1885,9 @@ void LayerTreeHostImpl::OnCanDrawStateChangedForTree() {
viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
viz::CompositorFrameMetadata metadata;
-
- if (active_tree_->request_presentation_time()) {
- metadata.presentation_token = ++last_presentation_token_;
- // Assume there is never a constant stream of requests that triggers
- // overflow.
- CHECK_NE(0u, last_presentation_token_);
- presentation_token_to_frame_[last_presentation_token_] =
- active_tree_->source_frame_number();
- }
+ metadata.frame_token = next_frame_token_++;
+ if (!next_frame_token_)
+ next_frame_token_ = 1u;
metadata.device_scale_factor = active_tree_->painted_device_scale_factor() *
active_tree_->device_scale_factor();
@@ -1867,6 +1910,16 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
active_tree_->GetViewportSelection(&metadata.selection);
+ if (active_tree_->has_presentation_callbacks() ||
+ settings_.always_request_presentation_time) {
+ metadata.request_presentation_feedback = true;
+ frame_token_infos_.emplace_back(metadata.frame_token,
+ CurrentBeginFrameArgs().frame_time,
+ active_tree_->TakePresentationCallbacks());
+
+ DCHECK_LE(frame_token_infos_.size(), 25u);
+ }
+
if (const auto* outer_viewport_scroll_node = OuterViewportScrollNode()) {
metadata.root_overflow_y_hidden =
!outer_viewport_scroll_node->user_scrollable_vertical;
@@ -1877,8 +1930,13 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
IsActivelyScrolling() || mutator_host_->NeedsTickAnimations();
}
- for (auto& surface_id : active_tree_->SurfaceLayerIds())
- metadata.referenced_surfaces.push_back(surface_id);
+ const base::flat_set<viz::SurfaceRange>& referenced_surfaces =
+ active_tree_->SurfaceRanges();
+ for (auto& surface_range : referenced_surfaces)
+ metadata.referenced_surfaces.push_back(surface_range);
+
+ if (last_draw_referenced_surfaces_ != referenced_surfaces)
+ last_draw_referenced_surfaces_ = referenced_surfaces;
const auto* inner_viewport_scroll_node = InnerViewportScrollNode();
if (!inner_viewport_scroll_node)
@@ -1894,15 +1952,21 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
return metadata;
}
-RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata() {
+RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata(
+ FrameData* frame) {
RenderFrameMetadata metadata;
metadata.root_scroll_offset =
gfx::ScrollOffsetToVector2dF(active_tree_->TotalScrollOffset());
+
metadata.root_background_color = active_tree_->background_color();
metadata.is_scroll_offset_at_top = active_tree_->TotalScrollOffset().y() == 0;
metadata.device_scale_factor = active_tree_->painted_device_scale_factor() *
active_tree_->device_scale_factor();
+ active_tree_->GetViewportSelection(&metadata.selection);
+ metadata.is_mobile_optimized = IsMobileOptimized(active_tree_.get());
metadata.viewport_size_in_pixels = device_viewport_size();
+
+#if defined(OS_ANDROID)
metadata.top_controls_height =
browser_controls_offset_manager_->TopControlsHeight();
metadata.top_controls_shown_ratio =
@@ -1911,8 +1975,28 @@ RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata() {
browser_controls_offset_manager_->BottomControlsHeight();
metadata.bottom_controls_shown_ratio =
browser_controls_offset_manager_->BottomControlsShownRatio();
+ metadata.scrollable_viewport_size = active_tree_->ScrollableViewportSize();
+ metadata.page_scale_factor = active_tree_->current_page_scale_factor();
+ metadata.min_page_scale_factor = active_tree_->min_page_scale_factor();
+ metadata.max_page_scale_factor = active_tree_->max_page_scale_factor();
+ metadata.root_layer_size = active_tree_->ScrollableSize();
+ if (const auto* outer_viewport_scroll_node = OuterViewportScrollNode()) {
+ metadata.root_overflow_y_hidden =
+ !outer_viewport_scroll_node->user_scrollable_vertical;
+ }
+ const auto* inner_viewport_scroll_node = InnerViewportScrollNode();
+ if (inner_viewport_scroll_node) {
+ metadata.root_overflow_y_hidden |=
+ !inner_viewport_scroll_node->user_scrollable_vertical;
+ }
+ metadata.has_transparent_background =
+ frame->render_passes.back()->has_transparent_background;
+#endif
bool allocate_new_local_surface_id =
+#if !defined(OS_ANDROID)
+ false;
+#else
last_draw_render_frame_metadata_ &&
(last_draw_render_frame_metadata_->top_controls_height !=
metadata.top_controls_height ||
@@ -1921,7 +2005,11 @@ RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata() {
last_draw_render_frame_metadata_->bottom_controls_height !=
metadata.bottom_controls_height ||
last_draw_render_frame_metadata_->bottom_controls_shown_ratio !=
- metadata.bottom_controls_shown_ratio);
+ metadata.bottom_controls_shown_ratio ||
+ last_draw_render_frame_metadata_->selection != metadata.selection ||
+ last_draw_render_frame_metadata_->has_transparent_background !=
+ metadata.has_transparent_background);
+#endif
viz::LocalSurfaceId local_surface_id =
child_local_surface_id_allocator_.GetCurrentLocalSurfaceId();
@@ -1931,19 +2019,14 @@ RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata() {
metadata.local_surface_id = local_surface_id;
}
- active_tree_->GetViewportSelection(&metadata.selection);
- metadata.is_mobile_optimized = IsMobileOptimized(active_tree_.get());
-
return metadata;
}
bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
DCHECK(CanDraw());
DCHECK_EQ(frame->has_no_damage, frame->render_passes.empty());
-
- TRACE_EVENT0("cc,benchmark", "LayerTreeHostImpl::DrawLayers");
-
ResetRequiresHighResToDraw();
+ skipped_frame_tracker_.DidProduceFrame();
if (frame->has_no_damage) {
DCHECK(!resourceless_software_draw_);
@@ -1953,6 +2036,36 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
return false;
}
+ auto compositor_frame = GenerateCompositorFrame(frame);
+ layer_tree_frame_sink_->SubmitCompositorFrame(std::move(compositor_frame));
+
+ // Clears the list of swap promises after calling DidSwap on each of them to
+ // signal that the swap is over.
+ active_tree()->ClearSwapPromises();
+
+ // The next frame should start by assuming nothing has changed, and changes
+ // are noted as they occur.
+ // TODO(boliu): If we did a temporary software renderer frame, propogate the
+ // damage forward to the next frame.
+ for (size_t i = 0; i < frame->render_surface_list->size(); i++) {
+ auto* surface = (*frame->render_surface_list)[i];
+ surface->damage_tracker()->DidDrawDamagedArea();
+ }
+ active_tree_->ResetAllChangeTracking();
+
+ active_tree_->set_has_ever_been_drawn(true);
+ devtools_instrumentation::DidDrawFrame(id_);
+ benchmark_instrumentation::IssueImplThreadRenderingStatsEvent(
+ rendering_stats_instrumentation_->TakeImplThreadRenderingStats());
+ return true;
+}
+
+viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
+ FrameData* frame) {
+ TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
+ TRACE_ID_GLOBAL(CurrentBeginFrameArgs().trace_id),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "step", "GenerateCompositorFrame");
base::TimeTicks frame_time = CurrentBeginFrameArgs().frame_time;
fps_counter_->SaveTimeStamp(frame_time,
!layer_tree_frame_sink_->context_provider());
@@ -1992,7 +2105,7 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
if (active_tree_->hud_layer()) {
TRACE_EVENT0("cc", "DrawLayers.UpdateHudTexture");
active_tree_->hud_layer()->UpdateHudTexture(
- draw_mode, layer_tree_frame_sink_, resource_provider_.get(),
+ draw_mode, layer_tree_frame_sink_, &resource_provider_,
// The hud uses Gpu rasterization if the device is capable, not related
// to the content of the web page.
gpu_rasterization_status_ != GpuRasterizationStatus::OFF_DEVICE,
@@ -2007,28 +2120,29 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
frame->use_default_lower_bound_deadline);
metadata.activation_dependencies = std::move(frame->activation_dependencies);
- active_tree()->FinishSwapPromises(&metadata, &frame_token_allocator_);
+ active_tree()->FinishSwapPromises(&metadata);
+ // The swap-promises should not change the frame-token.
+ DCHECK_EQ(metadata.frame_token + 1, next_frame_token_);
if (render_frame_metadata_observer_) {
- last_draw_render_frame_metadata_ = MakeRenderFrameMetadata();
+ last_draw_render_frame_metadata_ = MakeRenderFrameMetadata(frame);
render_frame_metadata_observer_->OnRenderFrameSubmission(
- *last_draw_render_frame_metadata_);
+ *last_draw_render_frame_metadata_, &metadata);
}
metadata.latency_info.emplace_back(ui::SourceEventType::FRAME);
ui::LatencyInfo& new_latency_info = metadata.latency_info.back();
if (CommitToActiveTree()) {
new_latency_info.AddLatencyNumberWithTimestamp(
- ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, 0, frame_time, 1);
+ ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, frame_time, 1);
} else {
new_latency_info.AddLatencyNumberWithTimestamp(
- ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, 0, frame_time,
- 1);
+ ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, frame_time, 1);
base::TimeTicks draw_time = base::TimeTicks::Now();
for (auto& latency : metadata.latency_info) {
latency.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, draw_time, 1);
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, draw_time, 1);
}
}
ui::LatencyInfo::TraceIntermediateFlowEvents(metadata.latency_info,
@@ -2049,7 +2163,7 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
viz::CompositorFrame compositor_frame;
compositor_frame.metadata = std::move(metadata);
- resource_provider_->PrepareSendToParent(
+ resource_provider_.PrepareSendToParent(
resources, &compositor_frame.resource_list,
layer_tree_frame_sink_->context_provider());
compositor_frame.render_pass_list = std::move(frame->render_passes);
@@ -2077,35 +2191,14 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
total_quad_count);
}
- compositor_frame.metadata.frame_token =
- frame_token_allocator_.GetFrameTokenForSubmission();
-
- layer_tree_frame_sink_->SubmitCompositorFrame(std::move(compositor_frame));
-
- // Clears the list of swap promises after calling DidSwap on each of them to
- // signal that the swap is over.
- active_tree()->ClearSwapPromises();
-
- // The next frame should start by assuming nothing has changed, and changes
- // are noted as they occur.
- // TODO(boliu): If we did a temporary software renderer frame, propogate the
- // damage forward to the next frame.
- for (size_t i = 0; i < frame->render_surface_list->size(); i++) {
- auto* surface = (*frame->render_surface_list)[i];
- surface->damage_tracker()->DidDrawDamagedArea();
- }
- active_tree_->ResetAllChangeTracking();
-
- active_tree_->set_has_ever_been_drawn(true);
- devtools_instrumentation::DidDrawFrame(id_);
- benchmark_instrumentation::IssueImplThreadRenderingStatsEvent(
- rendering_stats_instrumentation_->TakeImplThreadRenderingStats());
- return true;
+ return compositor_frame;
}
void LayerTreeHostImpl::DidDrawAllLayers(const FrameData& frame) {
+ // TODO(lethalantidote): LayerImpl::DidDraw can be removed when
+ // VideoLayerImpl is removed.
for (size_t i = 0; i < frame.will_draw_layers.size(); ++i)
- frame.will_draw_layers[i]->DidDraw(resource_provider_.get());
+ frame.will_draw_layers[i]->DidDraw(&resource_provider_);
for (auto* it : video_frame_controllers_)
it->DidDrawFrame();
@@ -2293,6 +2386,7 @@ void LayerTreeHostImpl::UpdateTreeResourcesForGpuRasterizationIfNeeded() {
}
bool LayerTreeHostImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
+ impl_thread_phase_ = ImplThreadPhase::INSIDE_IMPL_FRAME;
current_begin_frame_tracker_.Start(args);
if (is_likely_to_require_a_draw_) {
@@ -2310,7 +2404,7 @@ bool LayerTreeHostImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
for (auto* it : video_frame_controllers_)
it->OnBeginFrame(args);
- impl_thread_phase_ = ImplThreadPhase::INSIDE_IMPL_FRAME;
+ skipped_frame_tracker_.BeginFrame(args.frame_time, args.interval);
bool recent_frame_had_no_damage =
consecutive_frame_with_damage_count_ < settings_.damaged_frame_limit;
@@ -2335,6 +2429,7 @@ bool LayerTreeHostImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
}
void LayerTreeHostImpl::DidFinishImplFrame() {
+ skipped_frame_tracker_.FinishFrame();
impl_thread_phase_ = ImplThreadPhase::IDLE;
current_begin_frame_tracker_.Finish();
tile_manager_.decoded_image_tracker().NotifyFrameFinished();
@@ -2346,13 +2441,19 @@ void LayerTreeHostImpl::DidNotProduceFrame(const viz::BeginFrameAck& ack) {
}
void LayerTreeHostImpl::UpdateViewportContainerSizes() {
+ // TODO(bokan): Make URL-bar bounds deltas work with Blink-generated property
+ // trees. https://crbug.com/850135.
+ if (!InnerViewportScrollNode())
+ return;
+
LayerImpl* inner_container = active_tree_->InnerViewportContainerLayer();
LayerImpl* outer_container = active_tree_->OuterViewportContainerLayer();
if (!inner_container)
return;
- ViewportAnchor anchor(InnerViewportScrollLayer(), OuterViewportScrollLayer());
+ ViewportAnchor anchor(InnerViewportScrollNode(), OuterViewportScrollLayer(),
+ active_tree_.get());
float top_controls_layout_height =
active_tree_->browser_controls_shrink_blink_size()
@@ -2382,8 +2483,7 @@ void LayerTreeHostImpl::UpdateViewportContainerSizes() {
gfx::Vector2dF amount_to_expand_scaled = gfx::ScaleVector2d(
amount_to_expand, 1.f / active_tree_->min_page_scale_factor());
outer_container->SetViewportBoundsDelta(amount_to_expand_scaled);
- active_tree_->InnerViewportScrollLayer()->SetViewportBoundsDelta(
- amount_to_expand_scaled);
+ InnerViewportScrollLayer()->SetViewportBoundsDelta(amount_to_expand_scaled);
anchor.ResetViewportToAnchoredPosition();
}
@@ -2500,8 +2600,8 @@ void LayerTreeHostImpl::DidLoseLayerTreeFrameSink() {
client_->DidLoseLayerTreeFrameSinkOnImplThread();
}
-bool LayerTreeHostImpl::HaveRootScrollLayer() const {
- return !!InnerViewportScrollLayer();
+bool LayerTreeHostImpl::HaveRootScrollNode() const {
+ return InnerViewportScrollNode();
}
LayerImpl* LayerTreeHostImpl::InnerViewportContainerLayer() const {
@@ -2513,11 +2613,7 @@ LayerImpl* LayerTreeHostImpl::InnerViewportScrollLayer() const {
}
ScrollNode* LayerTreeHostImpl::InnerViewportScrollNode() const {
- const auto* inner_viewport_scroll_layer = InnerViewportScrollLayer();
- if (!inner_viewport_scroll_layer)
- return nullptr;
- ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree;
- return scroll_tree.Node(inner_viewport_scroll_layer->scroll_tree_index());
+ return active_tree_->InnerViewportScrollNode();
}
LayerImpl* LayerTreeHostImpl::OuterViewportContainerLayer() const {
@@ -2529,12 +2625,7 @@ LayerImpl* LayerTreeHostImpl::OuterViewportScrollLayer() const {
}
ScrollNode* LayerTreeHostImpl::OuterViewportScrollNode() const {
- // TODO(pdr): Refactor this to work like InnerViewportScrollNode and access
- // OuterViewportScrollLayer instead of MainScrollLayer.
- if (!viewport()->MainScrollLayer())
- return nullptr;
- ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree;
- return scroll_tree.Node(viewport()->MainScrollLayer()->scroll_tree_index());
+ return active_tree_->OuterViewportScrollNode();
}
ScrollNode* LayerTreeHostImpl::CurrentlyScrollingNode() {
@@ -2648,6 +2739,12 @@ void LayerTreeHostImpl::ActivateSyncTree() {
DCHECK(!recycle_tree_);
pending_tree_.swap(recycle_tree_);
+ // ScrollTimelines track a scroll source (i.e. a scroll node in the scroll
+ // tree), whose ElementId may change between the active and pending trees.
+ // Therefore we must inform all ScrollTimelines when the pending tree is
+ // promoted to active.
+ mutator_host_->PromoteScrollTimelinesPendingToActive();
+
// If we commit to the active tree directly, this is already done during
// commit.
ActivateAnimations();
@@ -2702,6 +2799,23 @@ void LayerTreeHostImpl::ActivateStateForImages() {
tile_manager_.DidActivateSyncTree();
}
+void LayerTreeHostImpl::OnPurgeMemory() {
+ ReleaseTileResources();
+ active_tree_->OnPurgeMemory();
+ if (pending_tree_)
+ pending_tree_->OnPurgeMemory();
+ if (recycle_tree_)
+ recycle_tree_->OnPurgeMemory();
+
+ EvictAllUIResources();
+ if (image_decode_cache_) {
+ image_decode_cache_->SetShouldAggressivelyFreeResources(true);
+ image_decode_cache_->SetShouldAggressivelyFreeResources(false);
+ }
+ if (resource_pool_)
+ resource_pool_->OnPurgeMemory();
+}
+
void LayerTreeHostImpl::OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level) {
// Only work for low-end devices for now.
@@ -2713,15 +2827,7 @@ void LayerTreeHostImpl::OnMemoryPressure(
case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
break;
case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
- ReleaseTileResources();
- ReleaseTreeResources();
- ClearUIResources();
- if (image_decode_cache_) {
- image_decode_cache_->SetShouldAggressivelyFreeResources(true);
- image_decode_cache_->SetShouldAggressivelyFreeResources(false);
- }
- if (resource_pool_)
- resource_pool_->OnPurgeMemory();
+ OnPurgeMemory();
break;
}
}
@@ -2769,6 +2875,7 @@ void LayerTreeHostImpl::SetNeedsOneBeginImplFrame() {
void LayerTreeHostImpl::SetNeedsRedraw() {
NotifySwapPromiseMonitorsOfSetNeedsRedraw();
client_->SetNeedsRedrawOnImplThread();
+ skipped_frame_tracker_.WillProduceFrame();
}
ManagedMemoryPolicy LayerTreeHostImpl::ActualManagedMemoryPolicy() const {
@@ -2952,7 +3059,7 @@ LayerTreeHostImpl::TakeCompletedImageDecodeRequests() {
return result;
}
-void LayerTreeHostImpl::DidNavigate() {
+void LayerTreeHostImpl::ClearCaches() {
// It is safe to clear the decode policy tracking on navigations since it
// comes with an invalidation and the image ids are never re-used.
bool can_clear_decode_policy_tracking = true;
@@ -3003,16 +3110,10 @@ void LayerTreeHostImpl::ReleaseLayerTreeFrameSink() {
has_valid_layer_tree_frame_sink_ = false;
- // Since we will create a new resource provider, we cannot continue to use
- // the old resources (i.e. render_surfaces and texture IDs). Clear them
- // before we destroy the old resource provider.
ReleaseTreeResources();
-
- // Note: ui resource cleanup uses the |resource_provider_|.
CleanUpTileManagerResources();
resource_pool_ = nullptr;
ClearUIResources();
- resource_provider_ = nullptr;
if (layer_tree_frame_sink_->context_provider()) {
auto* gl = layer_tree_frame_sink_->context_provider()->ContextGL();
@@ -3022,21 +3123,46 @@ void LayerTreeHostImpl::ReleaseLayerTreeFrameSink() {
// Release any context visibility before we destroy the LayerTreeFrameSink.
SetContextVisibility(false);
+ bool all_resources_are_lost = layer_tree_frame_sink_->context_provider();
+
// 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.
layer_tree_frame_sink_->DetachFromClient();
layer_tree_frame_sink_ = nullptr;
+ // 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.
+ //
+ // 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.
+ //
+ // The assumption being made here is that the display compositor WILL NOT use
+ // any resources previously exported when the CompositorFrameSink is closed.
+ // This should be true as the connection is closed when the display compositor
+ // shuts down/crashes, or when it believes we are a malicious client in which
+ // case it will not display content from the previous CompositorFrameSink. If
+ // this assumption is violated, we may modify resources no longer considered
+ // as exported while the display compositor is still making use of them,
+ // leading to visual mistakes.
+ resource_provider_.ReleaseAllExportedResources(all_resources_are_lost);
+
// We don't know if the next LayerTreeFrameSink will support GPU
// rasterization. Make sure to clear the flag so that we force a
// re-computation.
use_gpu_rasterization_ = false;
}
-bool LayerTreeHostImpl::InitializeRenderer(
+bool LayerTreeHostImpl::InitializeFrameSink(
LayerTreeFrameSink* layer_tree_frame_sink) {
- TRACE_EVENT0("cc", "LayerTreeHostImpl::InitializeRenderer");
+ TRACE_EVENT0("cc", "LayerTreeHostImpl::InitializeFrameSink");
ReleaseLayerTreeFrameSink();
if (!layer_tree_frame_sink->BindToClient(this)) {
@@ -3058,25 +3184,17 @@ bool LayerTreeHostImpl::InitializeRenderer(
max_texture_size_ = 16 * 1024;
}
- resource_provider_ = std::make_unique<LayerTreeResourceProvider>(
- layer_tree_frame_sink_->context_provider(),
- layer_tree_frame_sink_->capabilities().delegated_sync_points_required);
resource_pool_ = std::make_unique<ResourcePool>(
- resource_provider_.get(), layer_tree_frame_sink_->context_provider(),
- GetTaskRunner(), ResourcePool::kDefaultExpirationDelay,
+ &resource_provider_, context_provider, GetTaskRunner(),
+ ResourcePool::kDefaultExpirationDelay,
settings_.disallow_non_exact_resource_reuse);
- // TODO(piman): Make oop raster always supported: http://crbug.com/786591
- use_oop_rasterization_ = settings_.enable_oop_rasterization;
- if (use_oop_rasterization_) {
- auto* context = layer_tree_frame_sink_->worker_context_provider();
- if (context) {
- viz::RasterContextProvider::ScopedRasterContextLock hold(context);
- use_oop_rasterization_ &=
- context->ContextCapabilities().supports_oop_raster;
- } else {
- use_oop_rasterization_ = false;
- }
+ auto* context = layer_tree_frame_sink_->worker_context_provider();
+ if (context) {
+ viz::RasterContextProvider::ScopedRasterContextLock hold(context);
+ use_oop_rasterization_ = context->ContextCapabilities().supports_oop_raster;
+ } else {
+ use_oop_rasterization_ = false;
}
// Since the new context may be capable of MSAA, update status here. We don't
@@ -3182,11 +3300,9 @@ float LayerTreeHostImpl::CurrentBrowserControlsShownRatio() const {
return active_tree_->CurrentBrowserControlsShownRatio();
}
-void LayerTreeHostImpl::BindToClient(InputHandlerClient* client,
- bool wheel_scroll_latching_enabled) {
+void LayerTreeHostImpl::BindToClient(InputHandlerClient* client) {
DCHECK(input_handler_client_ == nullptr);
input_handler_client_ = client;
- touchpad_and_wheel_scroll_latching_enabled_ = wheel_scroll_latching_enabled;
}
InputHandler::ScrollStatus LayerTreeHostImpl::TryScroll(
@@ -3363,6 +3479,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBeginImpl(
}
scroll_status.thread = SCROLL_ON_IMPL_THREAD;
mutator_host_->ScrollAnimationAbort();
+ is_animating_for_snap_ = false;
browser_controls_offset_manager_->ScrollBegin();
@@ -3668,8 +3785,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
// For the rest of the current scroll sequence, latch to the first node
// that scrolled while it still exists.
- if (touchpad_and_wheel_scroll_latching_enabled_ &&
- scroll_tree.FindNodeFromElementId(
+ if (scroll_tree.FindNodeFromElementId(
scroll_animating_latched_element_id_) &&
scroll_node->element_id != scroll_animating_latched_element_id_) {
continue;
@@ -3693,6 +3809,8 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
viewport()->ScrollAnimated(pending_delta, delayed_by);
// Viewport::ScrollAnimated returns pending_delta as long as it starts
// an animation.
+ did_scroll_x_for_scroll_gesture_ |= scrolled.x() != 0;
+ did_scroll_y_for_scroll_gesture_ |= scrolled.y() != 0;
if (scrolled == pending_delta) {
scroll_animating_latched_element_id_ = scroll_node->element_id;
return scroll_status;
@@ -3703,6 +3821,8 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
gfx::Vector2dF scroll_delta =
ComputeScrollDelta(*scroll_node, pending_delta);
if (ScrollAnimationCreate(scroll_node, scroll_delta, delayed_by)) {
+ did_scroll_x_for_scroll_gesture_ |= scroll_delta.x() != 0;
+ did_scroll_y_for_scroll_gesture_ |= scroll_delta.y() != 0;
scroll_animating_latched_element_id_ = scroll_node->element_id;
return scroll_status;
}
@@ -4041,7 +4161,7 @@ void LayerTreeHostImpl::UpdateImageDecodingHints(
void LayerTreeHostImpl::SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) {
render_frame_metadata_observer_ = std::move(observer);
- render_frame_metadata_observer_->BindToCurrentThread(&frame_token_allocator_);
+ render_frame_metadata_observer_->BindToCurrentThread();
}
InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
@@ -4235,6 +4355,8 @@ bool LayerTreeHostImpl::SnapAtScrollEnd() {
} else {
ScrollAnimationCreate(scroll_node, delta, base::TimeDelta());
}
+ DCHECK(!is_animating_for_snap_);
+ is_animating_for_snap_ = true;
return true;
}
@@ -4254,8 +4376,8 @@ gfx::ScrollOffset LayerTreeHostImpl::GetVisualScrollOffset(
bool LayerTreeHostImpl::GetSnapFlingInfo(
const gfx::Vector2dF& natural_displacement_in_viewport,
- gfx::Vector2dF* initial_offset,
- gfx::Vector2dF* target_offset) const {
+ gfx::Vector2dF* out_initial_offset,
+ gfx::Vector2dF* out_target_offset) const {
const ScrollNode* scroll_node = CurrentlyScrollingNode();
if (!scroll_node || !scroll_node->snap_container_data.has_value())
return false;
@@ -4265,7 +4387,7 @@ bool LayerTreeHostImpl::GetSnapFlingInfo(
gfx::Vector2dF natural_displacement_in_content =
gfx::ScaleVector2d(natural_displacement_in_viewport, 1.f / scale_factor);
- *initial_offset =
+ *out_initial_offset =
ScrollOffsetToVector2dF(GetVisualScrollOffset(*scroll_node));
bool did_scroll_x = did_scroll_x_for_scroll_gesture_ ||
@@ -4274,15 +4396,15 @@ bool LayerTreeHostImpl::GetSnapFlingInfo(
natural_displacement_in_content.y() != 0;
gfx::ScrollOffset snap_offset;
- if (!data.FindSnapPosition(
- gfx::ScrollOffset(*initial_offset + natural_displacement_in_content),
- did_scroll_x, did_scroll_y, &snap_offset)) {
+ if (!data.FindSnapPosition(gfx::ScrollOffset(*out_initial_offset +
+ natural_displacement_in_content),
+ did_scroll_x, did_scroll_y, &snap_offset)) {
return false;
}
- *target_offset = ScrollOffsetToVector2dF(snap_offset);
- target_offset->Scale(scale_factor);
- initial_offset->Scale(scale_factor);
+ *out_target_offset = ScrollOffsetToVector2dF(snap_offset);
+ out_target_offset->Scale(scale_factor);
+ out_initial_offset->Scale(scale_factor);
return true;
}
@@ -4294,6 +4416,7 @@ void LayerTreeHostImpl::ClearCurrentlyScrollingNode() {
accumulated_root_overscroll_ = gfx::Vector2dF();
did_scroll_x_for_scroll_gesture_ = false;
did_scroll_y_for_scroll_gesture_ = false;
+ is_animating_for_snap_ = false;
}
void LayerTreeHostImpl::ScrollEndImpl(ScrollState* scroll_state) {
@@ -4312,20 +4435,6 @@ void LayerTreeHostImpl::ScrollEnd(ScrollState* scroll_state, bool should_snap) {
ScrollEndImpl(scroll_state);
}
-InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() {
- InputHandler::ScrollStatus scroll_status;
- scroll_status.main_thread_scrolling_reasons =
- MainThreadScrollingReason::kNotScrollingOnMain;
- if (!CurrentlyScrollingNode()) {
- scroll_status.thread = SCROLL_IGNORED;
- scroll_status.main_thread_scrolling_reasons =
- MainThreadScrollingReason::kNoScrollingLayer;
- } else {
- scroll_status.thread = SCROLL_ON_IMPL_THREAD;
- }
- return scroll_status;
-}
-
void LayerTreeHostImpl::MouseDown() {
ScrollbarAnimationController* animation_controller =
ScrollbarAnimationControllerForElementId(
@@ -4378,8 +4487,8 @@ void LayerTreeHostImpl::MouseMoveAt(const gfx::Point& viewport_point) {
scroll_element_id = scroll_node->element_id;
// Scrollbars for the viewport are registered with the outer viewport layer.
- if (InnerViewportScrollLayer() && OuterViewportScrollLayer() &&
- scroll_element_id == InnerViewportScrollLayer()->element_id())
+ if (InnerViewportScrollNode() && OuterViewportScrollLayer() &&
+ scroll_element_id == InnerViewportScrollNode()->element_id)
scroll_element_id = OuterViewportScrollLayer()->element_id();
}
@@ -4427,7 +4536,7 @@ void LayerTreeHostImpl::PinchGestureBegin() {
void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta,
const gfx::Point& anchor) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::PinchGestureUpdate");
- if (!InnerViewportScrollLayer())
+ if (!InnerViewportScrollNode())
return;
viewport()->PinchUpdate(magnify_delta, anchor);
client_->SetNeedsCommitOnImplThread();
@@ -4455,27 +4564,23 @@ void LayerTreeHostImpl::PinchGestureEnd(const gfx::Point& anchor,
SetNeedsRedraw();
}
-static void CollectScrollDeltas(ScrollAndScaleSet* scroll_info,
- LayerTreeImpl* tree_impl) {
- if (tree_impl->LayerListIsEmpty())
+void LayerTreeHostImpl::CollectScrollDeltas(
+ ScrollAndScaleSet* scroll_info) const {
+ if (active_tree_->LayerListIsEmpty())
return;
ElementId inner_viewport_scroll_element_id =
- tree_impl->InnerViewportScrollLayer()
- ? tree_impl->InnerViewportScrollLayer()->element_id()
- : ElementId();
+ InnerViewportScrollNode() ? InnerViewportScrollNode()->element_id
+ : ElementId();
- tree_impl->property_trees()->scroll_tree.CollectScrollDeltas(
+ active_tree_->property_trees()->scroll_tree.CollectScrollDeltas(
scroll_info, inner_viewport_scroll_element_id);
}
-static void CollectScrollbarUpdates(
- ScrollAndScaleSet* scroll_info,
- std::unordered_map<ElementId,
- std::unique_ptr<ScrollbarAnimationController>,
- ElementIdHash>* controllers) {
- scroll_info->scrollbars.reserve(controllers->size());
- for (auto& pair : *controllers) {
+void LayerTreeHostImpl::CollectScrollbarUpdates(
+ ScrollAndScaleSet* scroll_info) const {
+ scroll_info->scrollbars.reserve(scrollbar_animation_controllers_.size());
+ for (auto& pair : scrollbar_animation_controllers_) {
scroll_info->scrollbars.push_back(LayerTreeHostCommon::ScrollbarsUpdateInfo(
pair.first, pair.second->ScrollbarsHidden()));
}
@@ -4484,10 +4589,15 @@ static void CollectScrollbarUpdates(
std::unique_ptr<ScrollAndScaleSet> LayerTreeHostImpl::ProcessScrollDeltas() {
std::unique_ptr<ScrollAndScaleSet> scroll_info(new ScrollAndScaleSet());
- CollectScrollDeltas(scroll_info.get(), active_tree_.get());
- CollectScrollbarUpdates(scroll_info.get(), &scrollbar_animation_controllers_);
+ CollectScrollDeltas(scroll_info.get());
+ CollectScrollbarUpdates(scroll_info.get());
scroll_info->page_scale_delta =
active_tree_->page_scale_factor()->PullDeltaForMainThread();
+ // We should never process non-unit page_scale_delta for an OOPIF subframe.
+ // TODO(wjmaclean): Remove this DCHECK as a pre-condition to closing the bug.
+ // https://crbug.com/845097
+ DCHECK(!settings().is_layer_tree_for_subframe ||
+ scroll_info->page_scale_delta == 1.f);
scroll_info->top_controls_delta =
active_tree()->top_controls_shown_ratio()->PullDeltaForMainThread();
scroll_info->elastic_overscroll_delta =
@@ -4568,8 +4678,8 @@ bool LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time,
const ScrollTree& scroll_tree =
is_active_tree ? active_tree_->property_trees()->scroll_tree
: pending_tree_->property_trees()->scroll_tree;
- const bool animated =
- mutator_host_->TickAnimations(monotonic_time, scroll_tree);
+ const bool animated = mutator_host_->TickAnimations(
+ monotonic_time, scroll_tree, is_active_tree);
// TODO(crbug.com/551134): Only do this if the animations are on the active
// tree, or if they are on the pending tree waiting for some future time to
@@ -4654,11 +4764,11 @@ LayerTreeHostImpl::ScrollbarAnimationControllerForElementId(
// The viewport layers have only one set of scrollbars. On Android, these are
// registered with the inner viewport, otherwise they're registered with the
// outer viewport. If a controller for one exists, the other shouldn't.
- if (InnerViewportScrollLayer() && OuterViewportScrollLayer()) {
- if (scroll_element_id == InnerViewportScrollLayer()->element_id() ||
+ if (InnerViewportScrollNode() && OuterViewportScrollLayer()) {
+ if (scroll_element_id == InnerViewportScrollNode()->element_id ||
scroll_element_id == OuterViewportScrollLayer()->element_id()) {
auto itr = scrollbar_animation_controllers_.find(
- InnerViewportScrollLayer()->element_id());
+ InnerViewportScrollNode()->element_id);
if (itr != scrollbar_animation_controllers_.end())
return itr->second.get();
@@ -4972,16 +5082,15 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
if (layer_tree_frame_sink_->context_provider()) {
gpu::gles2::GLES2Interface* gl =
layer_tree_frame_sink_->context_provider()->ContextGL();
- gpu::Mailbox mailbox = gpu::Mailbox::Generate();
+ gpu::Mailbox mailbox;
gl->ProduceTextureDirectCHROMIUM(texture_alloc.texture_id, mailbox.name);
gpu::SyncToken sync_token =
- LayerTreeResourceProvider::GenerateSyncTokenHelper(gl);
+ viz::ClientResourceProvider::GenerateSyncTokenHelper(gl);
transferable = viz::TransferableResource::MakeGLOverlay(
mailbox, GL_LINEAR, texture_alloc.texture_target, sync_token,
upload_size, texture_alloc.overlay_candidate);
transferable.format = format;
- transferable.buffer_format = viz::BufferFormat(format);
} else {
mojo::ScopedSharedBufferHandle memory_handle =
viz::bitmap_allocation::DuplicateAndCloseMappedBitmap(
@@ -4992,7 +5101,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
upload_size, format);
}
transferable.color_space = color_space;
- id = resource_provider_->ImportResource(
+ id = resource_provider_.ImportResource(
transferable,
// The OnUIResourceReleased method is bound with a WeakPtr, but the
// resource backing will be deleted when the LayerTreeFrameSink is
@@ -5019,11 +5128,12 @@ void LayerTreeHostImpl::DeleteUIResource(UIResourceId uid) {
UIResourceData& data = it->second;
viz::ResourceId id = data.resource_id_for_export;
// Move the |data| to |deleted_ui_resources_| before removing it from the
- // LayerTreeResourceProvider, so that the ReleaseCallback can see it there.
+ // viz::ClientResourceProvider, so that the ReleaseCallback can see it
+ // there.
deleted_ui_resources_[uid] = std::move(data);
ui_resource_map_.erase(it);
- resource_provider_->RemoveImportedResource(id);
+ resource_provider_.RemoveImportedResource(id);
}
MarkUIResourceNotEvicted(uid);
}
@@ -5064,7 +5174,7 @@ void LayerTreeHostImpl::ClearUIResources() {
for (auto& pair : ui_resource_map_) {
UIResourceId uid = pair.first;
UIResourceData& data = pair.second;
- resource_provider_->RemoveImportedResource(data.resource_id_for_export);
+ resource_provider_.RemoveImportedResource(data.resource_id_for_export);
// Immediately drop the backing instead of waiting for the resource to be
// returned from the ResourceProvider, as this is called in cases where the
// ability to clean up the backings will go away (context loss, shutdown).
@@ -5174,18 +5284,11 @@ bool LayerTreeHostImpl::ScrollAnimationUpdateTarget(
bool LayerTreeHostImpl::IsElementInList(ElementId element_id,
ElementListType list_type) const {
- if (list_type == ElementListType::ACTIVE) {
- return active_tree()
- ? active_tree()->LayerByElementId(element_id) != nullptr
- : false;
- } else {
- if (pending_tree() && pending_tree()->LayerByElementId(element_id))
- return true;
- if (recycle_tree() && recycle_tree()->LayerByElementId(element_id))
- return true;
+ if (list_type == ElementListType::ACTIVE)
+ return active_tree() && active_tree()->IsElementInLayerList(element_id);
- return false;
- }
+ return (pending_tree() && pending_tree()->IsElementInLayerList(element_id)) ||
+ (recycle_tree() && recycle_tree()->IsElementInLayerList(element_id));
}
void LayerTreeHostImpl::SetMutatorsNeedCommit() {}
@@ -5288,7 +5391,7 @@ void LayerTreeHostImpl::ScrollOffsetAnimationFinished() {
// TODO(majidvp): We should pass in the original starting scroll position here
ScrollStateData scroll_state_data;
ScrollState scroll_state(scroll_state_data);
- ScrollEndImpl(&scroll_state);
+ ScrollEnd(&scroll_state, !is_animating_for_snap_);
}
gfx::ScrollOffset LayerTreeHostImpl::GetScrollOffsetForAnimation(
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index 3f93eb51e60..d2d9d750c8b 100644
--- a/chromium/cc/trees/layer_tree_host_impl.h
+++ b/chromium/cc/trees/layer_tree_host_impl.h
@@ -15,8 +15,10 @@
#include <vector>
#include "base/callback.h"
+#include "base/containers/circular_deque.h"
#include "base/containers/flat_map.h"
#include "base/macros.h"
+#include "base/memory/memory_coordinator_client.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/sequenced_task_runner.h"
#include "base/time/time.h"
@@ -27,7 +29,6 @@
#include "cc/input/input_handler.h"
#include "cc/input/scrollbar_animation_controller.h"
#include "cc/layers/layer_collections.h"
-#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/resources/ui_resource_client.h"
#include "cc/scheduler/begin_frame_tracker.h"
#include "cc/scheduler/commit_earlyout_reason.h"
@@ -36,8 +37,8 @@
#include "cc/tiles/decoded_image_tracker.h"
#include "cc/tiles/image_decode_cache.h"
#include "cc/tiles/tile_manager.h"
-#include "cc/trees/frame_token_allocator.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
+#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_mutator.h"
#include "cc/trees/layer_tree_settings.h"
#include "cc/trees/managed_memory_policy.h"
@@ -45,19 +46,23 @@
#include "cc/trees/render_frame_metadata.h"
#include "cc/trees/task_runner_provider.h"
#include "cc/trees/ukm_manager.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/gpu/context_cache_controller.h"
#include "components/viz/common/quads/render_pass.h"
#include "components/viz/common/surfaces/child_local_surface_id_allocator.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_range.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/latency/frame_metrics.h"
namespace gfx {
class ScrollOffset;
}
namespace viz {
+class CompositorFrame;
class CompositorFrameMetadata;
}
@@ -135,7 +140,8 @@ class LayerTreeHostImplClient {
virtual void DidCompletePageScaleAnimationOnImplThread() = 0;
// Called when output surface asks for a draw.
- virtual void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw) = 0;
+ virtual void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,
+ bool skip_draw) = 0;
virtual void NeedsImplSideInvalidation(
bool needs_first_draw_on_activation) = 0;
@@ -144,13 +150,12 @@ class LayerTreeHostImplClient {
virtual void RequestBeginMainFrameNotExpected(bool new_state) = 0;
- // Called when a presentation time is requested. |source_frames| identifies
- // the frames that correspond to the request.
+ // Called when a presentation time is requested. |frame_token| identifies
+ // the frame that was presented.
virtual void DidPresentCompositorFrameOnImplThread(
- const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) = 0;
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback) = 0;
protected:
virtual ~LayerTreeHostImplClient() {}
@@ -166,7 +171,8 @@ class CC_EXPORT LayerTreeHostImpl
public ScrollbarAnimationControllerClient,
public VideoFrameControllerClient,
public MutatorHostClient,
- public base::SupportsWeakPtr<LayerTreeHostImpl> {
+ public base::SupportsWeakPtr<LayerTreeHostImpl>,
+ public base::MemoryCoordinatorClient {
public:
// This structure is used to build all the state required for producing a
// single CompositorFrame. The |render_passes| list becomes the set of
@@ -230,8 +236,7 @@ class CC_EXPORT LayerTreeHostImpl
~LayerTreeHostImpl() override;
// InputHandler implementation
- void BindToClient(InputHandlerClient* client,
- bool wheel_scroll_latching_enabled) override;
+ void BindToClient(InputHandlerClient* client) override;
InputHandler::ScrollStatus ScrollBegin(
ScrollState* scroll_state,
InputHandler::ScrollInputType type) override;
@@ -249,7 +254,6 @@ class CC_EXPORT LayerTreeHostImpl
void SetSynchronousInputHandlerRootScrollOffset(
const gfx::ScrollOffset& root_offset) override;
void ScrollEnd(ScrollState* scroll_state, bool should_snap = false) override;
- InputHandler::ScrollStatus FlingScrollBegin() override;
void MouseDown() override;
void MouseUp() override;
@@ -275,6 +279,7 @@ class CC_EXPORT LayerTreeHostImpl
EventListenerTypeForTouchStartOrMoveAt(
const gfx::Point& viewport_port,
TouchAction* out_touch_action) override;
+ bool HasWheelEventHandlerAt(const gfx::Point& viewport_point) const override;
std::unique_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
ui::LatencyInfo* latency) override;
ScrollElasticityHelper* CreateScrollElasticityHelper() override;
@@ -289,7 +294,7 @@ class CC_EXPORT LayerTreeHostImpl
void SetCurrentBrowserControlsShownRatio(float offset) override;
float CurrentBrowserControlsShownRatio() const override;
void DidChangeBrowserControlsPosition() override;
- bool HaveRootScrollLayer() const override;
+ bool HaveRootScrollNode() const override;
void UpdateViewportContainerSizes();
@@ -309,7 +314,6 @@ class CC_EXPORT LayerTreeHostImpl
void ActivateAnimations();
void Animate();
void AnimatePendingTreeAfterCommit();
- void MainThreadHasStoppedFlinging();
void DidAnimateScrollOffset();
void SetFullViewportDamage();
void SetViewportDamage(const gfx::Rect& damage_rect);
@@ -318,7 +322,7 @@ class CC_EXPORT LayerTreeHostImpl
// add impl-side invalidations to it.
// virtual for testing.
virtual void InvalidateContentOnImplSide();
- virtual void InvalidateLayerTreeFrameSink();
+ virtual void InvalidateLayerTreeFrameSink(bool needs_redraw);
void SetTreeLayerScrollOffsetMutated(ElementId element_id,
LayerTreeImpl* tree,
@@ -363,6 +367,7 @@ class CC_EXPORT LayerTreeHostImpl
// called between the two.
virtual DrawResult PrepareToDraw(FrameData* frame);
virtual bool DrawLayers(FrameData* frame);
+ viz::CompositorFrame GenerateCompositorFrame(FrameData* frame);
// Must be called if and only if PrepareToDraw was called.
void DidDrawAllLayers(const FrameData& frame);
@@ -430,18 +435,17 @@ class CC_EXPORT LayerTreeHostImpl
base::Optional<viz::HitTestRegionList> BuildHitTestData() override;
void DidLoseLayerTreeFrameSink() override;
void DidReceiveCompositorFrameAck() override;
- void DidPresentCompositorFrame(uint32_t presentation_token,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) override;
- void DidDiscardCompositorFrame(uint32_t presentation_token) override;
+ void DidPresentCompositorFrame(
+ uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback) override;
void ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) override;
void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
void SetTreeActivationCallback(const base::Closure& callback) override;
void OnDraw(const gfx::Transform& transform,
const gfx::Rect& viewport,
- bool resourceless_software_draw) override;
+ bool resourceless_software_draw,
+ bool skip_draw) override;
// Called from LayerTreeImpl.
void OnCanDrawStateChangedForTree();
@@ -462,8 +466,7 @@ class CC_EXPORT LayerTreeHostImpl
int RequestedMSAASampleCount() const;
- // TODO(danakj): Rename this, there is no renderer.
- virtual bool InitializeRenderer(LayerTreeFrameSink* layer_tree_frame_sink);
+ virtual bool InitializeFrameSink(LayerTreeFrameSink* layer_tree_frame_sink);
TileManager* tile_manager() { return &tile_manager_; }
void SetHasGpuRasterizationTrigger(bool flag);
@@ -489,6 +492,8 @@ class CC_EXPORT LayerTreeHostImpl
return &image_animation_controller_;
}
+ uint32_t next_frame_token() const { return next_frame_token_; }
+
virtual bool WillBeginImplFrame(const viz::BeginFrameArgs& args);
virtual void DidFinishImplFrame();
void DidNotProduceFrame(const viz::BeginFrameAck& ack);
@@ -528,6 +533,10 @@ class CC_EXPORT LayerTreeHostImpl
virtual void SetVisible(bool visible);
bool visible() const { return visible_; }
+ bool is_animating_for_snap_for_testing() const {
+ return is_animating_for_snap_;
+ }
+
void SetNeedsCommit() { client_->SetNeedsCommitOnImplThread(); }
void SetNeedsOneBeginImplFrame();
void SetNeedsRedraw();
@@ -548,8 +557,8 @@ class CC_EXPORT LayerTreeHostImpl
FrameRateCounter* fps_counter() { return fps_counter_.get(); }
MemoryHistory* memory_history() { return memory_history_.get(); }
DebugRectHistory* debug_rect_history() { return debug_rect_history_.get(); }
- LayerTreeResourceProvider* resource_provider() {
- return resource_provider_.get();
+ viz::ClientResourceProvider* resource_provider() {
+ return &resource_provider_;
}
BrowserControlsOffsetManager* browser_controls_manager() {
return browser_controls_offset_manager_.get();
@@ -607,8 +616,8 @@ class CC_EXPORT LayerTreeHostImpl
gfx::ScrollOffset GetVisualScrollOffset(const ScrollNode& scroll_node) const;
bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement_in_viewport,
- gfx::Vector2dF* initial_offset,
- gfx::Vector2dF* target_offset) const override;
+ gfx::Vector2dF* out_initial_offset,
+ gfx::Vector2dF* out_target_offset) const override;
// Returns the amount of delta that can be applied to scroll_node, taking
// page scale into account.
@@ -618,7 +627,7 @@ class CC_EXPORT LayerTreeHostImpl
void ScheduleMicroBenchmark(std::unique_ptr<MicroBenchmarkImpl> benchmark);
viz::CompositorFrameMetadata MakeCompositorFrameMetadata();
- RenderFrameMetadata MakeRenderFrameMetadata();
+ RenderFrameMetadata MakeRenderFrameMetadata(FrameData* frame);
// Viewport rectangle and clip in device space. These rects are used to
// prioritize raster and determine what is submitted in a CompositorFrame.
@@ -688,7 +697,7 @@ class CC_EXPORT LayerTreeHostImpl
void QueueImageDecode(int request_id, const PaintImage& image);
std::vector<std::pair<int, bool>> TakeCompletedImageDecodeRequests();
- void DidNavigate();
+ void ClearCaches();
bool CanConsumeDelta(const ScrollNode& scroll_node,
const ScrollState& scroll_state);
@@ -727,12 +736,15 @@ class CC_EXPORT LayerTreeHostImpl
// Removes empty or orphan RenderPasses from the frame.
static void RemoveRenderPasses(FrameData* frame);
- LayerTreeHostImplClient* client_;
- TaskRunnerProvider* task_runner_provider_;
+ LayerTreeHostImplClient* const client_;
+ TaskRunnerProvider* const task_runner_provider_;
BeginFrameTracker current_begin_frame_tracker_;
private:
+ void CollectScrollDeltas(ScrollAndScaleSet* scroll_info) const;
+ void CollectScrollbarUpdates(ScrollAndScaleSet* scroll_info) const;
+
// Transforms viewport start point and scroll delta to local start point and
// local delta, respectively. If the transformation of either the start or end
// point of a scroll is clipped, the function returns false.
@@ -861,9 +873,22 @@ class CC_EXPORT LayerTreeHostImpl
// active tree.
void ActivateStateForImages();
+ // Overriden from base::MemoryCoordinatorClient.
+ void OnPurgeMemory() override;
+
+ // TODO(gyuyoung): OnMemoryPressure is deprecated. So this should be removed
+ // when the memory coordinator is enabled by default.
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level);
+ const LayerTreeSettings settings_;
+ const bool is_synchronous_single_threaded_;
+
+ const int default_color_space_id_ = gfx::ColorSpace::GetNextId();
+ const gfx::ColorSpace default_color_space_ = gfx::ColorSpace::CreateSRGB();
+
+ viz::ClientResourceProvider resource_provider_;
+
std::unordered_map<UIResourceId, UIResourceData> ui_resource_map_;
// UIResources are held here once requested to be deleted until they are
// released from the display compositor, then the backing can be deleted.
@@ -892,15 +917,15 @@ class CC_EXPORT LayerTreeHostImpl
std::unique_ptr<viz::ContextCacheController::ScopedVisibility>
worker_context_visibility_;
- std::unique_ptr<LayerTreeResourceProvider> resource_provider_;
- bool need_update_gpu_rasterization_status_;
- bool content_has_slow_paths_;
- bool content_has_non_aa_paint_;
- bool has_gpu_rasterization_trigger_;
- bool use_gpu_rasterization_;
- bool use_oop_rasterization_;
- bool use_msaa_;
- GpuRasterizationStatus gpu_rasterization_status_;
+ bool need_update_gpu_rasterization_status_ = false;
+ bool content_has_slow_paths_ = false;
+ bool content_has_non_aa_paint_ = false;
+ bool has_gpu_rasterization_trigger_ = false;
+ bool use_gpu_rasterization_ = false;
+ bool use_oop_rasterization_ = false;
+ bool use_msaa_ = false;
+ GpuRasterizationStatus gpu_rasterization_status_ =
+ GpuRasterizationStatus::OFF_DEVICE;
std::unique_ptr<RasterBufferProvider> raster_buffer_provider_;
std::unique_ptr<ResourcePool> resource_pool_;
std::unique_ptr<ImageDecodeCache> image_decode_cache_;
@@ -918,10 +943,10 @@ class CC_EXPORT LayerTreeHostImpl
// by the next sync from the main thread.
std::unique_ptr<LayerTreeImpl> recycle_tree_;
- InputHandlerClient* input_handler_client_;
- bool did_lock_scrolling_layer_;
- bool wheel_scrolling_;
- bool scroll_affects_scroll_handler_;
+ InputHandlerClient* input_handler_client_ = nullptr;
+ bool did_lock_scrolling_layer_ = false;
+ bool wheel_scrolling_ = false;
+ bool scroll_affects_scroll_handler_ = false;
ElementId scroll_element_id_mouse_currently_over_;
ElementId scroll_element_id_mouse_currently_captured_;
@@ -932,14 +957,12 @@ class CC_EXPORT LayerTreeHostImpl
// hold all state related to elasticity. May be NULL if never requested.
std::unique_ptr<ScrollElasticityHelper> scroll_elasticity_helper_;
- bool tile_priorities_dirty_;
+ bool tile_priorities_dirty_ = false;
- const LayerTreeSettings settings_;
LayerTreeDebugState debug_state_;
- bool visible_;
+ bool visible_ = false;
ManagedMemoryPolicy cached_managed_memory_policy_;
- const bool is_synchronous_single_threaded_;
TileManager tile_manager_;
gfx::Vector2dF accumulated_root_overscroll_;
@@ -949,8 +972,8 @@ class CC_EXPORT LayerTreeHostImpl
bool did_scroll_x_for_scroll_gesture_;
bool did_scroll_y_for_scroll_gesture_;
- bool pinch_gesture_active_;
- bool pinch_gesture_end_should_clear_scrolling_node_;
+ bool pinch_gesture_active_ = false;
+ bool pinch_gesture_end_should_clear_scrolling_node_ = false;
std::unique_ptr<BrowserControlsOffsetManager>
browser_controls_offset_manager_;
@@ -963,7 +986,7 @@ class CC_EXPORT LayerTreeHostImpl
// The maximum memory that would be used by the prioritized resource
// manager, if there were no limit on memory usage.
- size_t max_memory_needed_bytes_;
+ size_t max_memory_needed_bytes_ = 0;
// Viewport size passed in from the main thread, in physical pixels. This
// value is the default size for all concepts of physical viewport (draw
@@ -985,7 +1008,7 @@ class CC_EXPORT LayerTreeHostImpl
gfx::Transform external_transform_;
gfx::Rect external_viewport_;
gfx::Rect viewport_rect_for_tile_priority_;
- bool resourceless_software_draw_;
+ bool resourceless_software_draw_ = false;
gfx::Rect viewport_damage_rect_;
@@ -1012,12 +1035,12 @@ class CC_EXPORT LayerTreeHostImpl
std::set<SwapPromiseMonitor*> swap_promise_monitor_;
- bool requires_high_res_to_draw_;
- bool is_likely_to_require_a_draw_;
+ bool requires_high_res_to_draw_ = false;
+ bool is_likely_to_require_a_draw_ = false;
// TODO(danakj): Delete the LayerTreeFrameSink and all resources when
// it's lost instead of having this bool.
- bool has_valid_layer_tree_frame_sink_;
+ bool has_valid_layer_tree_frame_sink_ = false;
// If it is enabled in the LayerTreeSettings, we can check damage in
// WillBeginImplFrame and abort early if there is no damage. We only check
@@ -1046,12 +1069,10 @@ class CC_EXPORT LayerTreeHostImpl
// These are used to transfer usage of touch and wheel scrolls to the main
// thread.
- bool has_scrolled_by_wheel_;
- bool has_scrolled_by_touch_;
-
- bool touchpad_and_wheel_scroll_latching_enabled_;
+ bool has_scrolled_by_wheel_ = false;
+ bool has_scrolled_by_touch_ = false;
- ImplThreadPhase impl_thread_phase_;
+ ImplThreadPhase impl_thread_phase_ = ImplThreadPhase::IDLE;
ImageAnimationController image_animation_controller_;
@@ -1060,26 +1081,42 @@ class CC_EXPORT LayerTreeHostImpl
// Provides RenderFrameMetadata to the Browser process upon the submission of
// each CompositorFrame.
std::unique_ptr<RenderFrameMetadataObserver> render_frame_metadata_observer_;
- FrameTokenAllocator frame_token_allocator_;
-
- // Maps from presentation_token set on CF to the source frame that requested
- // it. Presentation tokens are requested if the active tree has
- // request_presentation_time() set.
- base::flat_map<uint32_t, int> presentation_token_to_frame_;
- // If non-zero identifies the presentation-token added to the last CF. Reset
- // to zero when no more presentation tokens are in flight.
- uint32_t last_presentation_token_ = 0u;
+ uint32_t next_frame_token_ = 1u;
viz::LocalSurfaceId last_draw_local_surface_id_;
+ base::flat_set<viz::SurfaceRange> last_draw_referenced_surfaces_;
base::Optional<RenderFrameMetadata> last_draw_render_frame_metadata_;
viz::ChildLocalSurfaceIdAllocator child_local_surface_id_allocator_;
- const int default_color_space_id_;
- const gfx::ColorSpace default_color_space_;
-
std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+ // Stores information needed once we get a response for a particular
+ // presentation token.
+ struct FrameTokenInfo {
+ FrameTokenInfo(
+ uint32_t token,
+ base::TimeTicks cc_frame_time,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks);
+ FrameTokenInfo(FrameTokenInfo&&);
+ ~FrameTokenInfo();
+
+ uint32_t token;
+
+ // The compositor frame time used to produce the frame.
+ base::TimeTicks cc_frame_time;
+
+ // The callbacks to send back to the main thread.
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameTokenInfo);
+ };
+
+ base::circular_deque<FrameTokenInfo> frame_token_infos_;
+ ui::FrameMetrics frame_metrics_;
+ ui::SkippedFrameTracker skipped_frame_tracker_;
+ bool is_animating_for_snap_;
+
DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl);
};
diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
index b7fdefd87dc..e59987d0bda 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -18,7 +18,7 @@
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/run_loop.h"
-#include "base/test/histogram_tester.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/animation/animation_host.h"
@@ -77,7 +77,6 @@
#include "components/viz/test/begin_frame_args_test.h"
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/test_layer_tree_frame_sink.h"
-#include "components/viz/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "media/base/media.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -100,7 +99,6 @@ using ::testing::AnyNumber;
using ::testing::AtLeast;
using ::testing::_;
using media::VideoFrame;
-using viz::TestWebGraphicsContext3D;
namespace cc {
namespace {
@@ -116,7 +114,7 @@ viz::SurfaceId MakeSurfaceId(const viz::FrameSinkId& frame_sink_id,
struct TestFrameData : public LayerTreeHostImpl::FrameData {
TestFrameData() {
// Set ack to something valid, so DCHECKs don't complain.
- begin_frame_ack = viz::BeginFrameAck(0, 1, true);
+ begin_frame_ack = viz::BeginFrameAck::CreateManualAckWithDamage();
}
};
@@ -193,7 +191,8 @@ class LayerTreeHostImplTest : public testing::Test,
void DidCompletePageScaleAnimationOnImplThread() override {
did_complete_page_scale_animation_ = true;
}
- void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw) override {
+ void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,
+ bool skip_draw) override {
std::unique_ptr<TestFrameData> frame(new TestFrameData);
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(frame.get()));
last_on_draw_render_passes_.clear();
@@ -209,10 +208,9 @@ class LayerTreeHostImplTest : public testing::Test,
void NotifyImageDecodeRequestFinished() override {}
void RequestBeginMainFrameNotExpected(bool new_state) override {}
void DidPresentCompositorFrameOnImplThread(
- const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) override {}
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback) override {}
void set_reduce_memory_result(bool reduce_memory_result) {
reduce_memory_result_ = reduce_memory_result;
@@ -244,7 +242,7 @@ class LayerTreeHostImplTest : public testing::Test,
image_worker_ ? image_worker_->task_runner() : nullptr);
layer_tree_frame_sink_ = std::move(layer_tree_frame_sink);
host_impl_->SetVisible(true);
- bool init = host_impl_->InitializeRenderer(layer_tree_frame_sink_.get());
+ bool init = host_impl_->InitializeFrameSink(layer_tree_frame_sink_.get());
host_impl_->SetViewportSize(gfx::Size(10, 10));
host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f);
host_impl_->active_tree()->SetLocalSurfaceIdFromParent(
@@ -693,9 +691,9 @@ class LayerTreeHostImplTest : public testing::Test,
SnapContainerData container_data(
ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
- gfx::ScrollOffset(300, 300));
- SnapAreaData area_data(SnapAxis::kBoth, gfx::ScrollOffset(50, 50),
- gfx::RectF(0, 0, 300, 300), false);
+ gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(300, 300));
+ SnapAreaData area_data(ScrollSnapAlign(SnapAlignment::kStart),
+ gfx::RectF(50, 50, 100, 100), false);
container_data.AddSnapAreaData(area_data);
overflow->test_properties()->snap_container_data.emplace(container_data);
host_impl_->active_tree()->BuildPropertyTreesForTesting();
@@ -807,7 +805,6 @@ class TestInputHandlerClient : public InputHandlerClient {
// InputHandlerClient implementation.
void WillShutdown() override {}
void Animate(base::TimeTicks time) override {}
- void MainThreadHasStoppedFlinging() override {}
void ReconcileElasticOverscrollAndRootScroll() override {}
void UpdateRootLayerStateForSynchronousInputHandler(
const gfx::ScrollOffset& total_scroll_offset,
@@ -900,7 +897,7 @@ TEST_F(LayerTreeHostImplTest, ResourcelessDrawWithEmptyViewport) {
gfx::Transform identity;
gfx::Rect viewport(100, 100);
const bool resourceless_software_draw = true;
- host_impl_->OnDraw(identity, viewport, resourceless_software_draw);
+ host_impl_->OnDraw(identity, viewport, resourceless_software_draw, false);
ASSERT_EQ(fake_layer_tree_frame_sink->num_sent_frames(), 1u);
EXPECT_EQ(
gfx::SizeF(100.f, 100.f),
@@ -1068,18 +1065,10 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) {
status.main_thread_scrolling_reasons);
}
-class LostGLES2Interface : public viz::TestGLES2Interface {
- public:
- LostGLES2Interface() = default;
-
- void InitializeTestContext() override {
- LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
- GL_INNOCENT_CONTEXT_RESET_ARB);
- }
-};
-
TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) {
- auto gl_owned = std::make_unique<LostGLES2Interface>();
+ auto gl_owned = std::make_unique<viz::TestGLES2Interface>();
+ gl_owned->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+ GL_INNOCENT_CONTEXT_RESET_ARB);
// Initialization will fail.
EXPECT_FALSE(
@@ -1124,8 +1113,9 @@ TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) {
}
TEST_F(LayerTreeHostImplTest, ScrollBlocksOnWheelEventHandlers) {
- SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ LayerImpl* scroll = SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
+ scroll->SetWheelEventHandlerRegion(Region(gfx::Rect(20, 20)));
DrawFrame();
// Wheel handlers determine whether mouse events block scroll.
@@ -1135,6 +1125,11 @@ TEST_F(LayerTreeHostImplTest, ScrollBlocksOnWheelEventHandlers) {
EventListenerProperties::kBlocking,
host_impl_->GetEventListenerProperties(EventListenerClass::kMouseWheel));
+ // LTHI should know the wheel event handler region and only block mouse events
+ // in that region.
+ EXPECT_TRUE(host_impl_->HasWheelEventHandlerAt(gfx::Point(10, 10)));
+ EXPECT_FALSE(host_impl_->HasWheelEventHandlerAt(gfx::Point(30, 30)));
+
// But they don't influence the actual handling of the scroll gestures.
InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
BeginState(gfx::Point()).get(), InputHandler::WHEEL);
@@ -1198,81 +1193,6 @@ TEST_F(LayerTreeHostImplTest, ScrollBlocksOnTouchEventHandlers) {
EXPECT_EQ(kTouchActionPanX, touch_action);
}
-TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) {
- SetupScrollAndContentsLayers(gfx::Size(100, 100));
- host_impl_->SetViewportSize(gfx::Size(50, 50));
- DrawFrame();
-
- // Ignore the fling since no layer is being scrolled
- InputHandler::ScrollStatus status = host_impl_->FlingScrollBegin();
- EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
- EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer,
- status.main_thread_scrolling_reasons);
-
- // Start scrolling a layer
- status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::TOUCHSCREEN);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
- EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
- status.main_thread_scrolling_reasons);
-
- // Now the fling should go ahead since we've started scrolling a layer
- status = host_impl_->FlingScrollBegin();
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
- EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
- status.main_thread_scrolling_reasons);
-}
-
-TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) {
- SetupScrollAndContentsLayers(gfx::Size(100, 100));
- host_impl_->SetViewportSize(gfx::Size(50, 50));
- DrawFrame();
-
- // Ignore the fling since no layer is being scrolled
- InputHandler::ScrollStatus status = host_impl_->FlingScrollBegin();
- EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
- EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer,
- status.main_thread_scrolling_reasons);
-
- // Start scrolling a layer
- status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::WHEEL);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
- EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
- status.main_thread_scrolling_reasons);
-
- // Now the fling should go ahead since we've started scrolling a layer
- status = host_impl_->FlingScrollBegin();
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
- EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
- status.main_thread_scrolling_reasons);
-}
-
-TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) {
- SetupScrollAndContentsLayers(gfx::Size(100, 100));
- host_impl_->SetViewportSize(gfx::Size(50, 50));
- LayerImpl* root = host_impl_->active_tree()->root_layer_for_testing();
-
- root->set_main_thread_scrolling_reasons(
- MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
-
- DrawFrame();
-
- // Start scrolling a layer
- InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
- BeginState(gfx::Point()).get(), InputHandler::TOUCHSCREEN);
- EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
- EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
- status.main_thread_scrolling_reasons);
-
- // The fling should be ignored since there's no layer being scrolled impl-side
- status = host_impl_->FlingScrollBegin();
- EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
- EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer,
- status.main_thread_scrolling_reasons);
-}
-
TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
@@ -1553,19 +1473,21 @@ TEST_F(LayerTreeHostImplTest, ScrollByReturnsCorrectValue) {
.did_scroll);
}
+// TODO(sunyunjia): Move scroll snap tests to a separate file.
+// https://crbug.com/851690
TEST_F(LayerTreeHostImplTest, ScrollSnapOnX) {
LayerImpl* overflow = CreateLayerForSnapping();
- gfx::Point scroll_position(10, 10);
+ gfx::Point pointer_position(10, 10);
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
gfx::Vector2dF x_delta(20, 0);
- host_impl_->ScrollBy(UpdateState(scroll_position, x_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get());
viz::BeginFrameArgs begin_frame_args =
viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
@@ -1584,16 +1506,16 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapOnX) {
TEST_F(LayerTreeHostImplTest, ScrollSnapOnY) {
LayerImpl* overflow = CreateLayerForSnapping();
- gfx::Point scroll_position(10, 10);
+ gfx::Point pointer_position(10, 10);
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
gfx::Vector2dF y_delta(0, 20);
- host_impl_->ScrollBy(UpdateState(scroll_position, y_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, y_delta).get());
viz::BeginFrameArgs begin_frame_args =
viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
@@ -1612,16 +1534,16 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapOnY) {
TEST_F(LayerTreeHostImplTest, ScrollSnapOnBoth) {
LayerImpl* overflow = CreateLayerForSnapping();
- gfx::Point scroll_position(10, 10);
+ gfx::Point pointer_position(10, 10);
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
gfx::Vector2dF delta(20, 20);
- host_impl_->ScrollBy(UpdateState(scroll_position, delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, delta).get());
viz::BeginFrameArgs begin_frame_args =
viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
@@ -1637,24 +1559,108 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapOnBoth) {
EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), overflow->CurrentScrollOffset());
}
+TEST_F(LayerTreeHostImplTest, ScrollSnapAfterAnimatedScroll) {
+ LayerImpl* overflow = CreateLayerForSnapping();
+
+ gfx::Point pointer_position(10, 10);
+ gfx::Vector2dF delta(20, 20);
+
+ EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+ host_impl_->ScrollAnimated(pointer_position, delta).thread);
+
+ EXPECT_EQ(overflow->scroll_tree_index(),
+ host_impl_->CurrentlyScrollingNode()->id);
+
+ base::TimeTicks start_time =
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(100);
+ viz::BeginFrameArgs begin_frame_args =
+ viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ BeginImplFrameAndAnimate(begin_frame_args, start_time);
+
+ // Animating for the wheel scroll.
+ BeginImplFrameAndAnimate(begin_frame_args,
+ start_time + base::TimeDelta::FromMilliseconds(50));
+ EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing());
+ gfx::ScrollOffset current_offset = overflow->CurrentScrollOffset();
+ EXPECT_LT(0, current_offset.x());
+ EXPECT_GT(20, current_offset.x());
+ EXPECT_LT(0, current_offset.y());
+ EXPECT_GT(20, current_offset.y());
+
+ // Animating for the snap.
+ BeginImplFrameAndAnimate(
+ begin_frame_args, start_time + base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_TRUE(host_impl_->is_animating_for_snap_for_testing());
+
+ // Finish the animation.
+ BeginImplFrameAndAnimate(
+ begin_frame_args, start_time + base::TimeDelta::FromMilliseconds(1500));
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), overflow->CurrentScrollOffset());
+ EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing());
+}
+
+TEST_F(LayerTreeHostImplTest, SnapAnimationCancelledByScroll) {
+ LayerImpl* overflow = CreateLayerForSnapping();
+
+ gfx::Point pointer_position(10, 10);
+ EXPECT_EQ(
+ InputHandler::SCROLL_ON_IMPL_THREAD,
+ host_impl_
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
+ .thread);
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
+
+ gfx::Vector2dF x_delta(20, 0);
+ host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get());
+ EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing());
+
+ viz::BeginFrameArgs begin_frame_args =
+ viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ host_impl_->ScrollEnd(EndState().get(), true);
+ base::TimeTicks start_time =
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(100);
+ BeginImplFrameAndAnimate(begin_frame_args, start_time);
+
+ // Animating for the snap.
+ BeginImplFrameAndAnimate(begin_frame_args,
+ start_time + base::TimeDelta::FromMilliseconds(100));
+ EXPECT_TRUE(host_impl_->is_animating_for_snap_for_testing());
+ gfx::ScrollOffset current_offset = overflow->CurrentScrollOffset();
+ EXPECT_GT(50, current_offset.x());
+ EXPECT_LT(20, current_offset.x());
+ EXPECT_EQ(0, current_offset.y());
+
+ // Interrup the snap animation with ScrollBegin.
+ EXPECT_EQ(
+ InputHandler::SCROLL_ON_IMPL_THREAD,
+ host_impl_
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
+ .thread);
+ EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing());
+ BeginImplFrameAndAnimate(begin_frame_args,
+ start_time + base::TimeDelta::FromMilliseconds(150));
+ EXPECT_VECTOR_EQ(ScrollOffsetToVector2dF(current_offset),
+ overflow->CurrentScrollOffset());
+}
+
TEST_F(LayerTreeHostImplTest, GetSnapFlingInfoWhenZoomed) {
LayerImpl* overflow = CreateLayerForSnapping();
// Scales the page to its 1/5.
host_impl_->active_tree()->PushPageScaleFromMainThread(0.2f, 0.1f, 5.f);
// Should be (10, 10) in the scroller's coordinate.
- gfx::Point scroll_position(2, 2);
+ gfx::Point pointer_position(2, 2);
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
// Should be (20, 20) in the scroller's coordinate.
gfx::Vector2dF delta(4, 4);
InputHandlerScrollResult result =
- host_impl_->ScrollBy(UpdateState(scroll_position, delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, delta).get());
EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), overflow->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(4, 4), result.current_visual_offset);
@@ -1684,13 +1690,13 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
scroll_layer->SetCurrentScrollOffset(gfx::ScrollOffset(30, 30));
DrawFrame();
- gfx::Point scroll_position(50, 50);
+ gfx::Point pointer_position(50, 50);
// OverscrollBehaviorTypeAuto shouldn't prevent scroll propagation.
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(30, 30), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(), overflow->CurrentScrollOffset());
@@ -1698,7 +1704,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
gfx::Vector2dF x_delta(-10, 0);
gfx::Vector2dF y_delta(0, -10);
gfx::Vector2dF diagonal_delta(-10, -10);
- host_impl_->ScrollBy(UpdateState(scroll_position, x_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get());
host_impl_->ScrollEnd(EndState().get());
EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 30), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
@@ -1715,12 +1721,12 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 30), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
- host_impl_->ScrollBy(UpdateState(scroll_position, x_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get());
host_impl_->ScrollEnd(EndState().get());
EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 30), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
@@ -1730,12 +1736,12 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 30), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
- host_impl_->ScrollBy(UpdateState(scroll_position, y_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, y_delta).get());
host_impl_->ScrollEnd(EndState().get());
EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
@@ -1745,12 +1751,12 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
- host_impl_->ScrollBy(UpdateState(scroll_position, diagonal_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, diagonal_delta).get());
host_impl_->ScrollEnd(EndState().get());
EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
@@ -1768,12 +1774,12 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
- host_impl_->ScrollBy(UpdateState(scroll_position, x_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get());
host_impl_->ScrollEnd(EndState().get());
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
@@ -1783,12 +1789,12 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
- host_impl_->ScrollBy(UpdateState(scroll_position, y_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, y_delta).get());
host_impl_->ScrollEnd(EndState().get());
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
@@ -1798,12 +1804,12 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
- host_impl_->ScrollBy(UpdateState(scroll_position, diagonal_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, diagonal_delta).get());
host_impl_->ScrollEnd(EndState().get());
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
@@ -1820,15 +1826,15 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
EXPECT_EQ(
InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
- ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL)
+ ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL)
.thread);
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset());
- host_impl_->ScrollBy(UpdateState(scroll_position, x_delta).get());
- host_impl_->ScrollBy(UpdateState(scroll_position, -x_delta).get());
- host_impl_->ScrollBy(UpdateState(scroll_position, y_delta).get());
- host_impl_->ScrollBy(UpdateState(scroll_position, -y_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, -x_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, y_delta).get());
+ host_impl_->ScrollBy(UpdateState(pointer_position, -y_delta).get());
host_impl_->ScrollEnd(EndState().get());
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->CurrentScrollOffset());
@@ -2602,7 +2608,7 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoomWheelBubbleBetweenViewports) {
TEST_F(LayerTreeHostImplTest, ScrollWithSwapPromises) {
ui::LatencyInfo latency_info;
latency_info.set_trace_id(5);
- latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0);
+ latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
std::unique_ptr<SwapPromise> swap_promise(
new LatencyInfoSwapPromise(latency_info));
@@ -3524,7 +3530,7 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest {
host_impl_ = base::WrapUnique(host_impl_override_time);
layer_tree_frame_sink_ = CreateLayerTreeFrameSink();
host_impl_->SetVisible(true);
- host_impl_->InitializeRenderer(layer_tree_frame_sink_.get());
+ host_impl_->InitializeFrameSink(layer_tree_frame_sink_.get());
SetupScrollAndContentsLayers(content_size);
host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f);
@@ -4404,12 +4410,15 @@ TEST_F(LayerTreeHostImplTest, ActivationDependenciesInMetadata) {
root->test_properties()->AddChild(std::move(child));
}
- base::flat_set<viz::SurfaceId> fallback_surfaces_set;
- for (size_t i = 0; i < fallback_surfaces.size(); ++i)
- fallback_surfaces_set.insert(fallback_surfaces[i]);
+ base::flat_set<viz::SurfaceRange> surfaces_set;
+ // |fallback_surfaces| and |primary_surfaces| should have same size
+ for (size_t i = 0; i < fallback_surfaces.size(); ++i) {
+ surfaces_set.insert(
+ viz::SurfaceRange(fallback_surfaces[i], primary_surfaces[i]));
+ }
host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->active_tree()->SetSurfaceLayerIds(fallback_surfaces_set);
+ host_impl_->active_tree()->SetSurfaceRanges(std::move(surfaces_set));
host_impl_->SetFullViewportDamage();
DrawFrame();
@@ -4424,7 +4433,9 @@ TEST_F(LayerTreeHostImplTest, ActivationDependenciesInMetadata) {
EXPECT_THAT(
metadata.referenced_surfaces,
testing::UnorderedElementsAre(
- fallback_surfaces[0], fallback_surfaces[1], fallback_surfaces[2]));
+ viz::SurfaceRange(fallback_surfaces[0], primary_surfaces[0]),
+ viz::SurfaceRange(fallback_surfaces[1], primary_surfaces[1]),
+ viz::SurfaceRange(fallback_surfaces[2], primary_surfaces[2])));
EXPECT_EQ(2u, metadata.deadline.deadline_in_frames());
EXPECT_FALSE(metadata.deadline.use_default_lower_bound_deadline());
}
@@ -4445,12 +4456,52 @@ TEST_F(LayerTreeHostImplTest, ActivationDependenciesInMetadata) {
EXPECT_THAT(
metadata.referenced_surfaces,
testing::UnorderedElementsAre(
- fallback_surfaces[0], fallback_surfaces[1], fallback_surfaces[2]));
+ viz::SurfaceRange(fallback_surfaces[0], primary_surfaces[0]),
+ viz::SurfaceRange(fallback_surfaces[1], primary_surfaces[1]),
+ viz::SurfaceRange(fallback_surfaces[2], primary_surfaces[2])));
EXPECT_EQ(0u, metadata.deadline.deadline_in_frames());
EXPECT_FALSE(metadata.deadline.use_default_lower_bound_deadline());
}
}
+// Verify that updating the set of referenced surfaces for the active tree
+// causes a new CompositorFrame to be submitted, even if there is no other
+// damage.
+TEST_F(LayerTreeHostImplTest, SurfaceReferencesChangeCausesDamage) {
+ SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ auto* fake_layer_tree_frame_sink =
+ static_cast<FakeLayerTreeFrameSink*>(host_impl_->layer_tree_frame_sink());
+
+ // Submit an initial CompositorFrame with an empty set of referenced surfaces.
+ host_impl_->active_tree()->BuildPropertyTreesForTesting();
+ host_impl_->active_tree()->SetSurfaceRanges({});
+ host_impl_->SetFullViewportDamage();
+ DrawFrame();
+
+ {
+ const viz::CompositorFrameMetadata& metadata =
+ fake_layer_tree_frame_sink->last_sent_frame()->metadata;
+ EXPECT_THAT(metadata.referenced_surfaces, testing::IsEmpty());
+ }
+
+ const viz::SurfaceId surface_id = MakeSurfaceId(viz::FrameSinkId(1, 1), 1);
+
+ // Update the set of referenced surfaces to contain |surface_id| but don't
+ // make any other changes that would cause damage. This mimics updating the
+ // SurfaceLayer for an offscreen tab.
+ host_impl_->active_tree()->BuildPropertyTreesForTesting();
+ host_impl_->active_tree()->SetSurfaceRanges({viz::SurfaceRange(surface_id)});
+ DrawFrame();
+
+ {
+ const viz::CompositorFrameMetadata& metadata =
+ fake_layer_tree_frame_sink->last_sent_frame()->metadata;
+ EXPECT_THAT(metadata.referenced_surfaces,
+ testing::UnorderedElementsAre(viz::SurfaceRange(surface_id)));
+ }
+}
+
TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
@@ -4586,11 +4637,13 @@ class DidDrawCheckLayer : public LayerImpl {
}
bool WillDraw(DrawMode draw_mode,
- LayerTreeResourceProvider* provider) override {
- will_draw_called_ = true;
+ viz::ClientResourceProvider* provider) override {
+ if (!LayerImpl::WillDraw(draw_mode, provider))
+ return false;
if (will_draw_returns_false_)
return false;
- return LayerImpl::WillDraw(draw_mode, provider);
+ will_draw_returned_true_ = true;
+ return true;
}
void AppendQuads(viz::RenderPass* render_pass,
@@ -4599,19 +4652,19 @@ class DidDrawCheckLayer : public LayerImpl {
LayerImpl::AppendQuads(render_pass, append_quads_data);
}
- void DidDraw(LayerTreeResourceProvider* provider) override {
+ void DidDraw(viz::ClientResourceProvider* provider) override {
did_draw_called_ = true;
LayerImpl::DidDraw(provider);
}
- bool will_draw_called() const { return will_draw_called_; }
+ bool will_draw_returned_true() const { return will_draw_returned_true_; }
bool append_quads_called() const { return append_quads_called_; }
bool did_draw_called() const { return did_draw_called_; }
void set_will_draw_returns_false() { will_draw_returns_false_ = true; }
void ClearDidDrawCheck() {
- will_draw_called_ = false;
+ will_draw_returned_true_ = false;
append_quads_called_ = false;
did_draw_called_ = false;
}
@@ -4625,7 +4678,7 @@ class DidDrawCheckLayer : public LayerImpl {
DidDrawCheckLayer(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id),
will_draw_returns_false_(false),
- will_draw_called_(false),
+ will_draw_returned_true_(false),
append_quads_called_(false),
did_draw_called_(false) {
SetBounds(gfx::Size(10, 10));
@@ -4635,7 +4688,7 @@ class DidDrawCheckLayer : public LayerImpl {
private:
bool will_draw_returns_false_;
- bool will_draw_called_;
+ bool will_draw_returned_true_;
bool append_quads_called_;
bool did_draw_called_;
};
@@ -4735,7 +4788,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) {
host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
- EXPECT_TRUE(layer->will_draw_called());
+ EXPECT_TRUE(layer->will_draw_returned_true());
EXPECT_TRUE(layer->append_quads_called());
EXPECT_TRUE(layer->did_draw_called());
}
@@ -4752,7 +4805,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) {
host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
- EXPECT_TRUE(layer->will_draw_called());
+ EXPECT_FALSE(layer->will_draw_returned_true());
EXPECT_FALSE(layer->append_quads_called());
EXPECT_FALSE(layer->did_draw_called());
}
@@ -4778,14 +4831,14 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) {
TestFrameData frame;
- EXPECT_FALSE(layer->will_draw_called());
+ EXPECT_FALSE(layer->will_draw_returned_true());
EXPECT_FALSE(layer->did_draw_called());
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
- EXPECT_FALSE(layer->will_draw_called());
+ EXPECT_FALSE(layer->will_draw_returned_true());
EXPECT_FALSE(layer->did_draw_called());
EXPECT_TRUE(layer->visible_layer_rect().IsEmpty());
@@ -4795,14 +4848,14 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) {
layer->NoteLayerPropertyChanged();
host_impl_->active_tree()->BuildPropertyTreesForTesting();
- EXPECT_FALSE(layer->will_draw_called());
+ EXPECT_FALSE(layer->will_draw_returned_true());
EXPECT_FALSE(layer->did_draw_called());
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
- EXPECT_TRUE(layer->will_draw_called());
+ EXPECT_TRUE(layer->will_draw_returned_true());
EXPECT_TRUE(layer->did_draw_called());
EXPECT_FALSE(layer->visible_layer_rect().IsEmpty());
@@ -4835,18 +4888,18 @@ TEST_F(LayerTreeHostImplTest, WillDrawNotCalledOnOccludedLayer) {
TestFrameData frame;
- EXPECT_FALSE(occluded_layer->will_draw_called());
+ EXPECT_FALSE(occluded_layer->will_draw_returned_true());
EXPECT_FALSE(occluded_layer->did_draw_called());
- EXPECT_FALSE(top_layer->will_draw_called());
+ EXPECT_FALSE(top_layer->will_draw_returned_true());
EXPECT_FALSE(top_layer->did_draw_called());
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
- EXPECT_FALSE(occluded_layer->will_draw_called());
+ EXPECT_FALSE(occluded_layer->will_draw_returned_true());
EXPECT_FALSE(occluded_layer->did_draw_called());
- EXPECT_TRUE(top_layer->will_draw_called());
+ EXPECT_TRUE(top_layer->will_draw_returned_true());
EXPECT_TRUE(top_layer->did_draw_called());
}
@@ -5110,7 +5163,7 @@ TEST_F(LayerTreeHostImplTest,
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
for (size_t i = 0; i < cases.size(); ++i) {
const auto& testcase = cases[i];
@@ -5133,7 +5186,7 @@ TEST_F(LayerTreeHostImplTest,
host_impl_->SetRequiresHighResToDraw();
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
}
}
@@ -6158,7 +6211,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest,
// Kick off an animation to show the browser controls.
host_impl_->browser_controls_manager()->UpdateBrowserControlsState(
- BOTH, SHOWN, true);
+ BrowserControlsState::kBoth, BrowserControlsState::kShown, true);
base::TimeTicks start_time = base::TimeTicks::Now();
viz::BeginFrameArgs begin_frame_args =
viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
@@ -6630,10 +6683,6 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) {
}
TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimatedLatchToChild) {
- // Enable wheel scroll latching flag.
- TestInputHandlerClient input_handler_client;
- host_impl_->BindToClient(&input_handler_client, true);
-
// Scroll a child layer beyond its maximum scroll range and make sure the
// parent layer isn't scrolled.
gfx::Size surface_size(100, 100);
@@ -6785,7 +6834,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::NON_BUBBLING_GESTURE)
+ InputHandler::TOUCHSCREEN)
.thread);
host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
host_impl_->ScrollEnd(EndState().get());
@@ -6814,7 +6863,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
- InputHandler::NON_BUBBLING_GESTURE)
+ InputHandler::TOUCHSCREEN)
.thread);
EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
grand_child->scroll_tree_index());
@@ -6839,7 +6888,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
- InputHandler::NON_BUBBLING_GESTURE)
+ InputHandler::TOUCHSCREEN)
.thread);
EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
grand_child->scroll_tree_index());
@@ -6866,7 +6915,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
->ScrollBegin(BeginState(gfx::Point(1, 1)).get(),
- InputHandler::NON_BUBBLING_GESTURE)
+ InputHandler::TOUCHSCREEN)
.thread);
EXPECT_EQ(grand_child->scroll_tree_index(),
host_impl_->CurrentlyScrollingNode()->id);
@@ -7327,7 +7376,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
scroll_layer->SetScrollable(gfx::Size(10, 20));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->BindToClient(&scroll_watcher, false);
+ host_impl_->BindToClient(&scroll_watcher);
gfx::Vector2dF initial_scroll_delta(10.f, 10.f);
scroll_layer->layer_tree_impl()
@@ -7459,6 +7508,44 @@ TEST_F(LayerTreeHostImplTest,
CheckLayerScrollDelta(scroll_layer, ScrollOffsetToVector2dF(scroll_offset));
}
+TEST_F(LayerTreeHostImplTest,
+ ExternalRootLayerScrollOffsetPreventedByUserNotScrollable) {
+ host_impl_->SetViewportSize(gfx::Size(10, 20));
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ LayerImpl* clip_layer =
+ scroll_layer->test_properties()->parent->test_properties()->parent;
+ clip_layer->SetBounds(gfx::Size(10, 20));
+ scroll_layer->SetScrollable(gfx::Size(10, 20));
+ scroll_layer->SetDrawsContent(true);
+ host_impl_->active_tree()
+ ->InnerViewportScrollLayer()
+ ->test_properties()
+ ->user_scrollable_vertical = false;
+ host_impl_->active_tree()
+ ->InnerViewportScrollLayer()
+ ->test_properties()
+ ->user_scrollable_horizontal = false;
+ host_impl_->active_tree()->BuildPropertyTreesForTesting();
+
+ // Draw first frame to clear any pending draws and check scroll.
+ DrawFrame();
+ CheckLayerScrollDelta(scroll_layer, gfx::Vector2dF(0.f, 0.f));
+ EXPECT_FALSE(host_impl_->active_tree()->needs_update_draw_properties());
+
+ // Set external scroll delta on delegate and notify LayerTreeHost.
+ gfx::ScrollOffset scroll_offset(10.f, 10.f);
+ host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset);
+ host_impl_->active_tree()->BuildPropertyTreesForTesting();
+
+ TestFrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+ host_impl_->DrawLayers(&frame);
+ host_impl_->DidDrawAllLayers(frame);
+ EXPECT_TRUE(frame.has_no_damage);
+ CheckLayerScrollDelta(scroll_layer,
+ ScrollOffsetToVector2dF(gfx::ScrollOffset()));
+}
+
TEST_F(LayerTreeHostImplTest, OverscrollRoot) {
InputHandlerScrollResult scroll_result;
SetupScrollAndContentsLayers(gfx::Size(100, 100));
@@ -7638,7 +7725,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::NON_BUBBLING_GESTURE)
+ InputHandler::TOUCHSCREEN)
.thread);
scroll_result =
host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
@@ -7653,7 +7740,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
- InputHandler::NON_BUBBLING_GESTURE)
+ InputHandler::TOUCHSCREEN)
.thread);
EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
grand_child_layer->scroll_tree_index());
@@ -7662,7 +7749,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
- InputHandler::NON_BUBBLING_GESTURE)
+ InputHandler::TOUCHSCREEN)
.thread);
scroll_result =
host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
@@ -7679,7 +7766,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
->ScrollBegin(BeginState(gfx::Point(5, 5)).get(),
- InputHandler::NON_BUBBLING_GESTURE)
+ InputHandler::TOUCHSCREEN)
.thread);
EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
grand_child_layer->scroll_tree_index());
@@ -7799,10 +7886,8 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) {
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
host_impl_
->ScrollBegin(BeginState(gfx::Point(0, 0)).get(),
- InputHandler::NON_BUBBLING_GESTURE)
+ InputHandler::TOUCHSCREEN)
.thread);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
scroll_result = host_impl_->ScrollBy(
UpdateState(gfx::Point(), gfx::Vector2dF(0, 20)).get());
EXPECT_TRUE(scroll_result.did_scroll);
@@ -8366,15 +8451,16 @@ class BlendStateCheckLayer : public LayerImpl {
public:
BlendStateCheckLayer(LayerTreeImpl* tree_impl,
int id,
- LayerTreeResourceProvider* resource_provider)
+ viz::ClientResourceProvider* resource_provider)
: LayerImpl(tree_impl, id),
+ resource_provider_(resource_provider),
blend_(false),
has_render_surface_(false),
comparison_layer_(nullptr),
quads_appended_(false),
quad_rect_(5, 5, 5, 5),
quad_visible_rect_(5, 5, 5, 5) {
- resource_id_ = resource_provider->ImportResource(
+ resource_id_ = resource_provider_->ImportResource(
viz::TransferableResource::MakeSoftware(
viz::SharedBitmap::GenerateId(), gfx::Size(1, 1), viz::RGBA_8888),
viz::SingleReleaseCallback::Create(base::DoNothing()));
@@ -8382,6 +8468,10 @@ class BlendStateCheckLayer : public LayerImpl {
SetDrawsContent(true);
}
+ void ReleaseResources() override {
+ resource_provider_->RemoveImportedResource(resource_id_);
+ }
+
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override {
quads_appended_ = true;
@@ -8428,6 +8518,7 @@ class BlendStateCheckLayer : public LayerImpl {
}
private:
+ viz::ClientResourceProvider* resource_provider_;
bool blend_;
bool has_render_surface_;
LayerImpl* comparison_layer_;
@@ -8831,7 +8922,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
gfx::Transform identity;
gfx::Rect viewport(viewport_size_);
bool resourceless_software_draw = true;
- host_impl_->OnDraw(identity, viewport, resourceless_software_draw);
+ host_impl_->OnDraw(identity, viewport, resourceless_software_draw, false);
VerifyEmptyLayerRenderPasses(last_on_draw_render_passes_);
}
@@ -8868,7 +8959,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
gfx::Transform identity;
gfx::Rect viewport(viewport_size_);
bool resourceless_software_draw = true;
- host_impl_->OnDraw(identity, viewport, resourceless_software_draw);
+ host_impl_->OnDraw(identity, viewport, resourceless_software_draw, false);
VerifyLayerInMiddleOfViewport(last_on_draw_render_passes_);
}
@@ -8905,7 +8996,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
gfx::Transform identity;
gfx::Rect viewport(viewport_size_);
bool resourceless_software_draw = true;
- host_impl_->OnDraw(identity, viewport, resourceless_software_draw);
+ host_impl_->OnDraw(identity, viewport, resourceless_software_draw, false);
VerifyLayerIsLargerThanViewport(last_on_draw_render_passes_);
}
@@ -9078,7 +9169,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
&task_graph_runner_,
AnimationHost::CreateForTesting(ThreadInstance::IMPL), 0, nullptr);
layer_tree_host_impl->SetVisible(true);
- layer_tree_host_impl->InitializeRenderer(layer_tree_frame_sink.get());
+ layer_tree_host_impl->InitializeFrameSink(layer_tree_frame_sink.get());
layer_tree_host_impl->WillBeginImplFrame(
viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2));
layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500));
@@ -9514,7 +9605,7 @@ TEST_F(LayerTreeHostImplTest,
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
EXPECT_EQ(1u, last_on_draw_frame_->will_draw_layers.size());
EXPECT_EQ(host_impl_->active_tree()->root_layer_for_testing(),
@@ -9549,7 +9640,7 @@ TEST_F(LayerTreeHostImplTest, MemoryLimits) {
// Gpu compositing.
layer_tree_frame_sink_ = FakeLayerTreeFrameSink::Create3d();
host_impl_->SetVisible(true);
- host_impl_->InitializeRenderer(layer_tree_frame_sink_.get());
+ host_impl_->InitializeFrameSink(layer_tree_frame_sink_.get());
{
const auto& state = host_impl_->global_tile_state();
EXPECT_EQ(kGpuByteLimit, state.hard_memory_limit_in_bytes);
@@ -9577,7 +9668,7 @@ TEST_F(LayerTreeHostImplTest, MemoryLimits) {
// Software compositing.
host_impl_->ReleaseLayerTreeFrameSink();
layer_tree_frame_sink_ = FakeLayerTreeFrameSink::CreateSoftware();
- host_impl_->InitializeRenderer(layer_tree_frame_sink_.get());
+ host_impl_->InitializeFrameSink(layer_tree_frame_sink_.get());
{
const auto& state = host_impl_->global_tile_state();
EXPECT_EQ(kGpuByteLimit, state.hard_memory_limit_in_bytes);
@@ -9694,7 +9785,7 @@ class LayerTreeHostImplTestPrepareTiles : public LayerTreeHostImplTest {
host_impl_.reset(fake_host_impl_);
layer_tree_frame_sink_ = CreateLayerTreeFrameSink();
host_impl_->SetVisible(true);
- host_impl_->InitializeRenderer(layer_tree_frame_sink_.get());
+ host_impl_->InitializeFrameSink(layer_tree_frame_sink_.get());
host_impl_->SetViewportSize(gfx::Size(10, 10));
}
@@ -9882,7 +9973,7 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) {
// in a texture mailbox.
ASSERT_TRUE(helper.unprocessed_result);
EXPECT_FALSE(context_provider->HasOneRef());
- EXPECT_EQ(1u, context_provider->TestContext3d()->NumTextures());
+ EXPECT_EQ(1u, context_provider->TestContextGL()->NumTextures());
host_impl_->ReleaseLayerTreeFrameSink();
host_impl_ = nullptr;
@@ -9890,214 +9981,13 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) {
// The texture release callback that was given to the CopyOutputResult has
// been canceled, and the texture deleted.
EXPECT_TRUE(context_provider->HasOneRef());
- EXPECT_EQ(0u, context_provider->TestContext3d()->NumTextures());
+ EXPECT_EQ(0u, context_provider->TestContextGL()->NumTextures());
// When resetting the CopyOutputResult, it will run its texture release
// callback. This should not cause a crash, etc.
helper.unprocessed_result.reset();
}
-TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) {
- // When flinging via touch, only the child should scroll (we should not
- // bubble).
- gfx::Size surface_size(10, 10);
- gfx::Size content_size(20, 20);
- const int kPageScaleLayerId = 4;
- const int kInnerViewportClipLayerId = 3;
- const int kInnerViewportScrollLayerId = 1;
- std::unique_ptr<LayerImpl> root_ptr =
- LayerImpl::Create(host_impl_->active_tree(), kPageScaleLayerId);
- std::unique_ptr<LayerImpl> root_clip =
- LayerImpl::Create(host_impl_->active_tree(), kInnerViewportClipLayerId);
- root_clip->test_properties()->force_render_surface = true;
-
- std::unique_ptr<LayerImpl> root_scroll =
- CreateScrollableLayer(kInnerViewportScrollLayerId, content_size);
- root_scroll->test_properties()->is_container_for_fixed_position_layers = true;
- std::unique_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size);
-
- root_scroll->test_properties()->AddChild(std::move(child));
- ElementId root_id = root_scroll->element_id();
- root_clip->test_properties()->AddChild(std::move(root_scroll));
- root_ptr->test_properties()->AddChild(std::move(root_clip));
-
- host_impl_->SetViewportSize(surface_size);
- host_impl_->active_tree()->SetRootLayerForTesting(std::move(root_ptr));
- LayerTreeImpl::ViewportLayerIds viewport_ids;
- viewport_ids.page_scale = kPageScaleLayerId;
- viewport_ids.inner_viewport_container = kInnerViewportClipLayerId;
- viewport_ids.inner_viewport_scroll = kInnerViewportScrollLayerId;
- host_impl_->active_tree()->SetViewportLayersFromIds(viewport_ids);
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->active_tree()->DidBecomeActive();
- DrawFrame();
- {
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::TOUCHSCREEN)
- .thread);
-
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
-
- gfx::Vector2d scroll_delta(0, 100);
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
-
- host_impl_->ScrollEnd(EndState().get());
-
- std::unique_ptr<ScrollAndScaleSet> scroll_info =
- host_impl_->ProcessScrollDeltas();
-
- // Only the child should have scrolled.
- ASSERT_EQ(1u, scroll_info->scrolls.size());
- ExpectNone(*scroll_info.get(), root_id);
- }
-}
-
-TEST_F(LayerTreeHostImplTest, TouchFlingShouldContinueScrollingCurrentLayer) {
- // Scroll a child layer beyond its maximum scroll range and make sure the
- // the scroll doesn't bubble up to the parent layer.
- gfx::Size surface_size(10, 10);
- LayerImpl* root =
- CreateBasicVirtualViewportLayers(surface_size, surface_size);
- root->test_properties()->force_render_surface = true;
-
- std::unique_ptr<LayerImpl> root_scrolling_owned =
- CreateScrollableLayer(12, surface_size);
- auto* root_scrolling = root_scrolling_owned.get();
- root->test_properties()->AddChild(std::move(root_scrolling_owned));
-
- std::unique_ptr<LayerImpl> child_owned =
- CreateScrollableLayer(13, surface_size);
- auto* child = child_owned.get();
- root_scrolling->test_properties()->AddChild(std::move(child_owned));
-
- std::unique_ptr<LayerImpl> grand_child_owned =
- CreateScrollableLayer(14, surface_size);
- auto* grand_child = grand_child_owned.get();
- child->test_properties()->AddChild(std::move(grand_child_owned));
-
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->active_tree()->DidBecomeActive();
-
- child->layer_tree_impl()
- ->property_trees()
- ->scroll_tree.UpdateScrollOffsetBaseForTesting(child->element_id(),
- gfx::ScrollOffset(0, 4));
- grand_child->layer_tree_impl()
- ->property_trees()
- ->scroll_tree.UpdateScrollOffsetBaseForTesting(grand_child->element_id(),
- gfx::ScrollOffset(0, 2));
-
- host_impl_->SetViewportSize(surface_size);
- DrawFrame();
- {
- std::unique_ptr<ScrollAndScaleSet> scroll_info;
-
- gfx::Vector2d scroll_delta(0, -2);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::TOUCHSCREEN)
- .thread);
- EXPECT_TRUE(
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
- .did_scroll);
-
- // The grand child should have scrolled up to its limit.
- scroll_info = host_impl_->ProcessScrollDeltas();
- ASSERT_EQ(1u, scroll_info->scrolls.size());
- ElementId grand_child_scroll_id =
- LayerIdToElementIdForTesting(grand_child->id());
- EXPECT_TRUE(
- ScrollInfoContains(*scroll_info, grand_child_scroll_id, scroll_delta));
- EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
- grand_child->scroll_tree_index());
-
- // The locked scrolling layer should remain set as the grand child.
- EXPECT_FALSE(
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
- .did_scroll);
- scroll_info = host_impl_->ProcessScrollDeltas();
- ASSERT_EQ(1u, scroll_info->scrolls.size());
- EXPECT_TRUE(
- ScrollInfoContains(*scroll_info, grand_child_scroll_id, scroll_delta));
- ExpectNone(*scroll_info, child->element_id());
- EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
- grand_child->scroll_tree_index());
-
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
- EXPECT_FALSE(
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
- .did_scroll);
- EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
- grand_child->scroll_tree_index());
-
- // The child should not have scrolled.
- scroll_info = host_impl_->ProcessScrollDeltas();
- ASSERT_EQ(1u, scroll_info->scrolls.size());
- EXPECT_TRUE(
- ScrollInfoContains(*scroll_info, grand_child_scroll_id, scroll_delta));
- ExpectNone(*scroll_info, child->element_id());
-
- // As the locked layer is at it's limit, no further scrolling can occur.
- EXPECT_FALSE(
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
- .did_scroll);
- EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
- grand_child->scroll_tree_index());
- host_impl_->ScrollEnd(EndState().get());
- }
-}
-
-TEST_F(LayerTreeHostImplTest, WheelFlingShouldntBubble) {
- // When flinging via wheel, we shouldn't bubble.
- gfx::Size surface_size(10, 10);
- gfx::Size content_size(20, 20);
- LayerImpl* root_clip =
- CreateBasicVirtualViewportLayers(surface_size, surface_size);
- root_clip->test_properties()->force_render_surface = true;
- std::unique_ptr<LayerImpl> root_scroll =
- CreateScrollableLayer(11, content_size);
- ElementId root_scroll_id = root_scroll->element_id();
- std::unique_ptr<LayerImpl> child = CreateScrollableLayer(12, content_size);
-
- root_scroll->test_properties()->AddChild(std::move(child));
- root_clip->test_properties()->AddChild(std::move(root_scroll));
-
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->active_tree()->DidBecomeActive();
-
- host_impl_->SetViewportSize(surface_size);
- DrawFrame();
- {
- EXPECT_EQ(
- InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL)
- .thread);
-
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
-
- gfx::Vector2d scroll_delta(0, 100);
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
-
- host_impl_->ScrollEnd(EndState().get());
-
- std::unique_ptr<ScrollAndScaleSet> scroll_info =
- host_impl_->ProcessScrollDeltas();
-
- // The root shouldn't have scrolled.
- ASSERT_EQ(1u, scroll_info->scrolls.size());
- ExpectNone(*scroll_info.get(), root_scroll_id);
- }
-}
-
TEST_F(LayerTreeHostImplTest, ScrollUnknownNotOnAncestorChain) {
// If we ray cast a scroller that is not on the first layer's ancestor chain,
// we should return SCROLL_UNKNOWN.
@@ -10246,15 +10136,15 @@ TEST_F(LayerTreeHostImplLatencyInfoRendererTest,
fake_layer_tree_frame_sink->last_sent_frame()->metadata.latency_info;
EXPECT_EQ(1u, metadata_latency_after1.size());
EXPECT_TRUE(metadata_latency_after1[0].FindLatency(
- ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, 0, nullptr));
+ ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, nullptr));
EXPECT_TRUE(metadata_latency_after1[0].FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, nullptr));
// The second frame should have the default BeginFrame component and the
// component attached via LatencyInfoSwapPromise.
ui::LatencyInfo latency_info;
latency_info.set_trace_id(5);
- latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0);
+ latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
std::unique_ptr<SwapPromise> swap_promise(
new LatencyInfoSwapPromise(latency_info));
host_impl_->active_tree()->QueuePinnedSwapPromise(std::move(swap_promise));
@@ -10270,15 +10160,15 @@ TEST_F(LayerTreeHostImplLatencyInfoRendererTest,
fake_layer_tree_frame_sink->last_sent_frame()->metadata.latency_info;
EXPECT_EQ(2u, metadata_latency_after2.size());
EXPECT_TRUE(metadata_latency_after2[0].FindLatency(
- ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, nullptr));
+ ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(metadata_latency_after2[1].FindLatency(
- ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, 0, nullptr));
+ ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, nullptr));
// Renderer should also record INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT.
EXPECT_TRUE(metadata_latency_after2[0].FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, nullptr));
EXPECT_TRUE(metadata_latency_after2[1].FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, nullptr));
}
// Make sure LatencyInfo are passed in viz::CompositorFrameMetadata properly in
@@ -10301,15 +10191,15 @@ TEST_F(LayerTreeHostImplLatencyInfoUITest,
fake_layer_tree_frame_sink->last_sent_frame()->metadata.latency_info;
EXPECT_EQ(1u, metadata_latency_after1.size());
EXPECT_TRUE(metadata_latency_after1[0].FindLatency(
- ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, 0, nullptr));
+ ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, nullptr));
EXPECT_FALSE(metadata_latency_after1[0].FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, nullptr));
// The second frame should have the default BeginFrame component and the
// component attached via LatencyInfoSwapPromise.
ui::LatencyInfo latency_info;
latency_info.set_trace_id(5);
- latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0);
+ latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
std::unique_ptr<SwapPromise> swap_promise(
new LatencyInfoSwapPromise(latency_info));
host_impl_->active_tree()->QueuePinnedSwapPromise(std::move(swap_promise));
@@ -10325,15 +10215,15 @@ TEST_F(LayerTreeHostImplLatencyInfoUITest,
fake_layer_tree_frame_sink->last_sent_frame()->metadata.latency_info;
EXPECT_EQ(2u, metadata_latency_after2.size());
EXPECT_TRUE(metadata_latency_after2[0].FindLatency(
- ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, nullptr));
+ ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(metadata_latency_after2[1].FindLatency(
- ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, 0, nullptr));
+ ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, nullptr));
// UI should not record INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT.
EXPECT_FALSE(metadata_latency_after2[0].FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, nullptr));
EXPECT_FALSE(metadata_latency_after2[1].FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, nullptr));
}
TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToCompositorFrameMetadata) {
@@ -10636,7 +10526,7 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest,
host_impl_->SetViewportSize(gfx::Size(100, 100));
host_impl_->browser_controls_manager()->UpdateBrowserControlsState(
- BOTH, SHOWN, false);
+ BrowserControlsState::kBoth, BrowserControlsState::kShown, false);
DrawFrame();
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
@@ -10711,7 +10601,7 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest,
host_impl_->SetViewportSize(gfx::Size(50, 100));
host_impl_->active_tree()->set_browser_controls_shrink_blink_size(true);
host_impl_->browser_controls_manager()->UpdateBrowserControlsState(
- BOTH, SHOWN, false);
+ BrowserControlsState::kBoth, BrowserControlsState::kShown, false);
DrawFrame();
LayerImpl* viewport_layer = host_impl_->InnerViewportScrollLayer();
@@ -10753,7 +10643,7 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest,
host_impl_->SetViewportSize(gfx::Size(100, 200));
host_impl_->browser_controls_manager()->UpdateBrowserControlsState(
- BOTH, SHOWN, false);
+ BrowserControlsState::kBoth, BrowserControlsState::kShown, false);
DrawFrame();
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
@@ -10833,7 +10723,7 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest,
host_impl_->SetViewportSize(gfx::Size(100, 100));
host_impl_->browser_controls_manager()->UpdateBrowserControlsState(
- BOTH, SHOWN, false);
+ BrowserControlsState::kBoth, BrowserControlsState::kShown, false);
float initial_scroll_offset = 50;
scroll_layer->layer_tree_impl()
->property_trees()
@@ -10905,84 +10795,6 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest,
}
TEST_F(LayerTreeHostImplWithBrowserControlsTest,
- BrowserControlsAnimationAfterMainThreadFlingStopped) {
- LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 200));
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
-
- host_impl_->SetViewportSize(gfx::Size(100, 100));
- host_impl_->browser_controls_manager()->UpdateBrowserControlsState(
- BOTH, SHOWN, false);
- float initial_scroll_offset = 50;
- scroll_layer->layer_tree_impl()
- ->property_trees()
- ->scroll_tree.UpdateScrollOffsetBaseForTesting(
- scroll_layer->element_id(),
- gfx::ScrollOffset(0, initial_scroll_offset));
- DrawFrame();
-
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::TOUCHSCREEN)
- .thread);
- EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset());
- EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
- scroll_layer->CurrentScrollOffset().ToString());
-
- // Scroll the browser controls partially.
- const float residue = 15;
- float offset = top_controls_height_ - residue;
- EXPECT_TRUE(
- host_impl_
- ->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, offset)).get())
- .did_scroll);
- EXPECT_FLOAT_EQ(-offset,
- host_impl_->browser_controls_manager()->ControlsTopOffset());
- EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
- scroll_layer->CurrentScrollOffset().ToString());
-
- did_request_redraw_ = false;
- did_request_next_frame_ = false;
- did_request_commit_ = false;
-
- // End the fling while the controls are still offset from the limit.
- host_impl_->MainThreadHasStoppedFlinging();
- ASSERT_TRUE(host_impl_->browser_controls_manager()->has_animation());
- EXPECT_TRUE(did_request_next_frame_);
- EXPECT_TRUE(did_request_redraw_);
- EXPECT_FALSE(did_request_commit_);
-
- // Animate the browser controls to the limit.
- viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(
- BEGINFRAME_FROM_HERE, 0, 1, base::TimeTicks::Now());
- while (did_request_next_frame_) {
- did_request_redraw_ = false;
- did_request_next_frame_ = false;
- did_request_commit_ = false;
-
- float old_offset =
- host_impl_->browser_controls_manager()->ControlsTopOffset();
-
- begin_frame_args.frame_time += base::TimeDelta::FromMilliseconds(5);
- begin_frame_args.sequence_number++;
- host_impl_->WillBeginImplFrame(begin_frame_args);
- host_impl_->Animate();
-
- float new_offset =
- host_impl_->browser_controls_manager()->ControlsTopOffset();
-
- if (new_offset != old_offset) {
- EXPECT_TRUE(did_request_redraw_);
- EXPECT_TRUE(did_request_commit_);
- }
- host_impl_->DidFinishImplFrame();
- }
- EXPECT_FALSE(host_impl_->browser_controls_manager()->has_animation());
- EXPECT_EQ(-top_controls_height_,
- host_impl_->browser_controls_manager()->ControlsTopOffset());
-}
-
-TEST_F(LayerTreeHostImplWithBrowserControlsTest,
BrowserControlsScrollDeltaInOverScroll) {
// Verifies that the overscroll delta should not have accumulated in
// the browser controls if we do a hide and show without releasing finger.
@@ -10991,7 +10803,7 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest,
host_impl_->SetViewportSize(gfx::Size(100, 100));
host_impl_->browser_controls_manager()->UpdateBrowserControlsState(
- BOTH, SHOWN, false);
+ BrowserControlsState::kBoth, BrowserControlsState::kShown, false);
DrawFrame();
EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
@@ -11240,81 +11052,6 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, ScrollBothInnerAndOuterLayer) {
}
}
-TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) {
- gfx::Size content_size = gfx::Size(200, 320);
- gfx::Size outer_viewport = gfx::Size(100, 160);
- gfx::Size inner_viewport = gfx::Size(50, 80);
-
- SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport);
-
- LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer();
- LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer();
-
- DrawFrame();
- {
- gfx::Vector2dF inner_expected;
- gfx::Vector2dF outer_expected;
- EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
- EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
-
- // Scrolling the viewport always sets the outer scroll layer as the
- // currently scrolling layer.
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::TOUCHSCREEN)
- .thread);
- EXPECT_EQ(outer_scroll->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
- EXPECT_EQ(outer_scroll->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
-
- 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 += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y());
- EXPECT_EQ(outer_scroll->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
-
- host_impl_->ScrollEnd(EndState().get());
- EXPECT_EQ(nullptr, host_impl_->CurrentlyScrollingNode());
-
- EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
- EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
-
- // Fling past the inner viewport boundry, make sure outer viewport scrolls.
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::TOUCHSCREEN)
- .thread);
- EXPECT_EQ(outer_scroll->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
- EXPECT_EQ(outer_scroll->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
-
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
- inner_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y());
- EXPECT_EQ(outer_scroll->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
-
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
- outer_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y());
- EXPECT_EQ(outer_scroll->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
-
- host_impl_->ScrollEnd(EndState().get());
- EXPECT_EQ(nullptr, host_impl_->CurrentlyScrollingNode());
-
- EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
- EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
- }
-}
-
TEST_F(LayerTreeHostImplVirtualViewportTest,
DiagonalScrollBubblesPerfectlyToInner) {
gfx::Size content_size = gfx::Size(200, 320);
@@ -11339,8 +11076,6 @@ TEST_F(LayerTreeHostImplVirtualViewportTest,
->ScrollBegin(BeginState(gfx::Point()).get(),
InputHandler::TOUCHSCREEN)
.thread);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(
gfx::Point(), InputHandler::TOUCHSCREEN));
@@ -11374,79 +11109,6 @@ TEST_F(LayerTreeHostImplVirtualViewportTest,
}
TEST_F(LayerTreeHostImplVirtualViewportTest,
- TouchFlingDoesntSwitchScrollingLayer) {
- gfx::Size content_size = gfx::Size(100, 160);
- gfx::Size outer_viewport = gfx::Size(50, 80);
- gfx::Size inner_viewport = gfx::Size(25, 40);
-
- SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport);
-
- LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer();
- LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer();
-
- std::unique_ptr<LayerImpl> child = CreateScrollableLayer(10, outer_viewport);
- LayerImpl* child_scroll = child.get();
- outer_scroll->test_properties()->children[0]->test_properties()->AddChild(
- std::move(child));
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
-
- ElementId child_scroll_id = LayerIdToElementIdForTesting(child_scroll->id());
-
- DrawFrame();
- {
- std::unique_ptr<ScrollAndScaleSet> scroll_info;
-
- gfx::Vector2d scroll_delta(0, inner_viewport.height());
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::TOUCHSCREEN)
- .thread);
- EXPECT_TRUE(
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
- .did_scroll);
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(), InputHandler::TOUCHSCREEN));
-
- // The child should have scrolled up to its limit.
- scroll_info = host_impl_->ProcessScrollDeltas();
- ASSERT_EQ(1u, scroll_info->scrolls.size());
- EXPECT_TRUE(
- ScrollInfoContains(*scroll_info, child_scroll_id, scroll_delta));
- EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
- child_scroll->scroll_tree_index());
-
- // The fling have no effect on the currently scrolling layer.
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
- EXPECT_FALSE(
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
- .did_scroll);
- EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
- child_scroll->scroll_tree_index());
- EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(), InputHandler::TOUCHSCREEN));
-
- // The inner viewport shouldn't have scrolled.
- scroll_info = host_impl_->ProcessScrollDeltas();
- ASSERT_EQ(1u, scroll_info->scrolls.size());
- EXPECT_TRUE(
- ScrollInfoContains(*scroll_info, child_scroll_id, scroll_delta));
- ExpectNone(*scroll_info, inner_scroll->element_id());
-
- // As the locked layer is at its limit, no further scrolling can occur.
- EXPECT_FALSE(
- host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get())
- .did_scroll);
- EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id,
- child_scroll->scroll_tree_index());
- host_impl_->ScrollEnd(EndState().get());
- EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(
- gfx::Point(), InputHandler::TOUCHSCREEN));
- }
-}
-
-TEST_F(LayerTreeHostImplVirtualViewportTest,
ScrollBeginEventThatTargetsViewportLayerSkipsHitTest) {
gfx::Size content_size = gfx::Size(100, 160);
gfx::Size outer_viewport = gfx::Size(50, 80);
@@ -11546,7 +11208,7 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformReflectedInNextDraw) {
host_impl_->SetExternalTilePriorityConstraints(external_viewport,
external_transform);
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
EXPECT_TRANSFORMATION_MATRIX_EQ(
external_transform, layer->draw_properties().target_space_transform);
@@ -11554,7 +11216,7 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformReflectedInNextDraw) {
host_impl_->SetExternalTilePriorityConstraints(external_viewport,
external_transform);
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
EXPECT_TRANSFORMATION_MATRIX_EQ(
external_transform, layer->draw_properties().target_space_transform);
}
@@ -11576,7 +11238,8 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformSetNeedsRedraw) {
// Clear any damage.
host_impl_->SetExternalTilePriorityConstraints(viewport_for_tile_priority1,
transform_for_tile_priority);
- host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw);
+ host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+ false);
last_on_draw_frame_.reset();
// Setting new constraints needs redraw.
@@ -11584,7 +11247,8 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformSetNeedsRedraw) {
host_impl_->SetExternalTilePriorityConstraints(viewport_for_tile_priority2,
transform_for_tile_priority);
EXPECT_TRUE(did_request_redraw_);
- host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw);
+ host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+ false);
EXPECT_FALSE(last_on_draw_frame_->has_no_damage);
}
@@ -11601,213 +11265,49 @@ TEST_F(LayerTreeHostImplTest, OnDrawConstraintSetNeedsRedraw) {
bool resourceless_software_draw = false;
// Clear any damage.
- host_impl_->OnDraw(draw_transform, draw_viewport1,
- resourceless_software_draw);
+ host_impl_->OnDraw(draw_transform, draw_viewport1, resourceless_software_draw,
+ false);
last_on_draw_frame_.reset();
// Same draw params does not swap.
did_request_redraw_ = false;
- host_impl_->OnDraw(draw_transform, draw_viewport1,
- resourceless_software_draw);
+ host_impl_->OnDraw(draw_transform, draw_viewport1, resourceless_software_draw,
+ false);
EXPECT_FALSE(did_request_redraw_);
EXPECT_TRUE(last_on_draw_frame_->has_no_damage);
last_on_draw_frame_.reset();
// Different draw params does swap.
did_request_redraw_ = false;
- host_impl_->OnDraw(draw_transform, draw_viewport2,
- resourceless_software_draw);
+ host_impl_->OnDraw(draw_transform, draw_viewport2, resourceless_software_draw,
+ false);
EXPECT_TRUE(did_request_redraw_);
EXPECT_FALSE(last_on_draw_frame_->has_no_damage);
}
-// TODO(gyuyoung): OnMemoryPressure disabled on ASAN, TSAN, Android, windows
-// due to the test failure. Will be handled on
-// http://crbug.com/839687.
-#if defined(OS_WIN) || defined(OS_ANDROID) || defined(ADDRESS_SANITIZER) || \
- defined(THREAD_SANITIZER) || defined(MEMORY_SANITIZER) || \
- defined(LEAK_SANITIZER)
-#define MAYBE_OnMemoryPressure DISABLED_OnMemoryPressure
-#else
-#define MAYBE_OnMemoryPressure OnMemoryPressure
-#endif
-
-TEST_F(LayerTreeHostImplTest, MAYBE_OnMemoryPressure) {
+TEST_F(LayerTreeHostImplTest, OnMemoryPressure) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableLowEndDeviceMode);
- const gfx::Size viewport_size(100, 100);
- host_impl_->SetViewportSize(viewport_size);
- host_impl_->CreatePendingTree();
- scoped_refptr<FakeRasterSource> raster_source(
- FakeRasterSource::CreateFilled(viewport_size));
- std::unique_ptr<FakePictureLayerImpl> layer(
- FakePictureLayerImpl::CreateWithRasterSource(host_impl_->pending_tree(),
- 11, raster_source));
- layer->SetBounds(viewport_size);
- layer->SetDrawsContent(true);
- host_impl_->pending_tree()->SetRootLayerForTesting(std::move(layer));
- host_impl_->pending_tree()->BuildPropertyTreesForTesting();
- host_impl_->ActivateSyncTree();
- const gfx::Transform draw_transform;
- host_impl_->OnDraw(draw_transform, gfx::Rect(viewport_size), false);
+ gfx::Size size(200, 200);
+ viz::ResourceFormat format = viz::RGBA_8888;
+ gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
+ ResourcePool::InUsePoolResource resource =
+ host_impl_->resource_pool()->AcquireResource(size, format, color_space);
+ host_impl_->resource_pool()->ReleaseResource(std::move(resource));
- std::unique_ptr<base::ProcessMetrics> metric(
- base::ProcessMetrics::CreateCurrentProcessMetrics());
- size_t current_memory_usage = metric->GetMallocUsage();
+ size_t current_memory_usage =
+ host_impl_->resource_pool()->GetTotalMemoryUsageForTesting();
base::MemoryPressureListener::SimulatePressureNotification(
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
base::RunLoop().RunUntilIdle();
- size_t memory_usage_after_memory_pressure = metric->GetMallocUsage();
+ size_t memory_usage_after_memory_pressure =
+ host_impl_->resource_pool()->GetTotalMemoryUsageForTesting();
// Memory usage after the memory pressure should be less than previous one.
EXPECT_LT(memory_usage_after_memory_pressure, current_memory_usage);
- EXPECT_FALSE(host_impl_->use_gpu_rasterization());
-}
-
-// We will force the touch event handler to be passive if we touch on a layer
-// which is the current scrolling layer.
-TEST_F(LayerTreeHostImplTest, TouchInsideFlingLayer) {
- gfx::Size surface_size(100, 100);
- gfx::Size content_size(200, 200);
-
- LayerImpl* root =
- CreateBasicVirtualViewportLayers(surface_size, surface_size);
- root->test_properties()->force_render_surface = true;
-
- // A div layer which has an event handler.
- std::unique_ptr<LayerImpl> child = CreateScrollableLayer(26, surface_size);
- LayerImpl* child_layer = child.get();
-
- // The layer tree should create a layer for the div layer, which is the
- // actual scrolling layer.
- std::unique_ptr<LayerImpl> grand_child =
- CreateScrollableLayer(27, content_size);
- LayerImpl* grand_child_layer = grand_child.get();
-
- child->test_properties()->AddChild(std::move(grand_child));
- root->test_properties()->AddChild(std::move(child));
-
- host_impl_->SetViewportSize(surface_size);
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->active_tree()->DidBecomeActive();
- DrawFrame();
-
- {
- TouchAction touch_action;
- // Touch on a layer which does not have a handler will return kNone.
- EXPECT_EQ(InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER,
- host_impl_->EventListenerTypeForTouchStartOrMoveAt(
- gfx::Point(10, 10), &touch_action));
- TouchActionRegion touch_action_region;
- touch_action_region.Union(kTouchActionNone, gfx::Rect(0, 0, 100, 100));
- child_layer->SetTouchActionRegion(touch_action_region);
- EXPECT_EQ(InputHandler::TouchStartOrMoveEventListenerType::HANDLER,
- host_impl_->EventListenerTypeForTouchStartOrMoveAt(
- gfx::Point(10, 10), &touch_action));
- // Flinging the grand_child layer.
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point(60, 60)).get(),
- InputHandler::TOUCHSCREEN)
- .thread);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
- EXPECT_EQ(grand_child_layer->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
- // Touch on the grand_child layer, which is an active fling layer, the touch
- // event handler will force to be passive.
- EXPECT_EQ(InputHandler::TouchStartOrMoveEventListenerType::
- HANDLER_ON_SCROLLING_LAYER,
- host_impl_->EventListenerTypeForTouchStartOrMoveAt(
- gfx::Point(70, 80), &touch_action));
- }
-}
-
-// We will force the touch event handler to be passive if we touch on a layer
-// which is a descendant of the current scrolling layer. If we touch on its
-// ancestor, then the touch event handler will still be blocked.
-TEST_F(LayerTreeHostImplTest, TouchInsideOrOutsideFlingLayer) {
- gfx::Size surface_size(100, 100);
- gfx::Size content_size(200, 200);
- gfx::Size inner_size(50, 50);
-
- LayerImpl* root =
- CreateBasicVirtualViewportLayers(surface_size, surface_size);
- root->test_properties()->force_render_surface = true;
-
- // A div layer which has an event handler.
- std::unique_ptr<LayerImpl> child = CreateScrollableLayer(26, surface_size);
- LayerImpl* child_layer = child.get();
-
- // The layer tree should create a layer for the div layer, which is the
- // actual scrolling layer.
- std::unique_ptr<LayerImpl> grand_child =
- CreateScrollableLayer(27, content_size);
- LayerImpl* grand_child_layer = grand_child.get();
-
- // A child scrollable layer inside grand_child_layer.
- std::unique_ptr<LayerImpl> great_grand_child =
- CreateScrollableLayer(28, inner_size);
- LayerImpl* great_grand_child_layer = great_grand_child.get();
-
- grand_child->test_properties()->AddChild(std::move(great_grand_child));
- child->test_properties()->AddChild(std::move(grand_child));
- root->test_properties()->AddChild(std::move(child));
-
- host_impl_->SetViewportSize(surface_size);
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->active_tree()->DidBecomeActive();
- DrawFrame();
-
- {
- TouchActionRegion touch_action_region;
- touch_action_region.Union(kTouchActionNone, gfx::Rect(0, 0, 100, 100));
- child_layer->SetTouchActionRegion(std::move(touch_action_region));
- touch_action_region = TouchActionRegion();
- touch_action_region.Union(kTouchActionNone, gfx::Rect(0, 0, 50, 50));
- grand_child_layer->SetTouchActionRegion(std::move(touch_action_region));
- // Flinging the grand_child layer.
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point(60, 60)).get(),
- InputHandler::TOUCHSCREEN)
- .thread);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
- EXPECT_EQ(grand_child_layer->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
- // Touch on the grand_child layer, which is an active fling layer, the touch
- // event handler will force to be passive.
- TouchAction touch_action;
- EXPECT_EQ(InputHandler::TouchStartOrMoveEventListenerType::
- HANDLER_ON_SCROLLING_LAYER,
- host_impl_->EventListenerTypeForTouchStartOrMoveAt(
- gfx::Point(70, 80), &touch_action));
- // Touch on the great_grand_child_layer layer, which is the child of the
- // active fling layer, the touch event handler will force to be passive.
- EXPECT_EQ(InputHandler::TouchStartOrMoveEventListenerType::
- HANDLER_ON_SCROLLING_LAYER,
- host_impl_->EventListenerTypeForTouchStartOrMoveAt(
- gfx::Point(20, 30), &touch_action));
-
- // Now flinging on the great_grand_child_layer.
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_
- ->ScrollBegin(BeginState(gfx::Point(10, 10)).get(),
- InputHandler::TOUCHSCREEN)
- .thread);
- EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
- host_impl_->FlingScrollBegin().thread);
- EXPECT_EQ(great_grand_child_layer->scroll_tree_index(),
- host_impl_->CurrentlyScrollingNode()->id);
- // Touch on the child layer, the touch event handler will be blocked.
- EXPECT_EQ(InputHandler::TouchStartOrMoveEventListenerType::HANDLER,
- host_impl_->EventListenerTypeForTouchStartOrMoveAt(
- gfx::Point(60, 60), &touch_action));
- }
}
class ResourcelessSoftwareLayerTreeHostImplTest : public LayerTreeHostImplTest {
@@ -11830,18 +11330,21 @@ TEST_F(ResourcelessSoftwareLayerTreeHostImplTest,
bool resourceless_software_draw = false;
// Clear any damage.
- host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw);
+ host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+ false);
last_on_draw_frame_.reset();
// Always swap even if same draw params.
resourceless_software_draw = true;
- host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw);
+ host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+ false);
EXPECT_FALSE(last_on_draw_frame_->has_no_damage);
last_on_draw_frame_.reset();
// Next hardware draw has damage.
resourceless_software_draw = false;
- host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw);
+ host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+ false);
EXPECT_FALSE(last_on_draw_frame_->has_no_damage);
}
@@ -11869,7 +11372,8 @@ TEST_F(ResourcelessSoftwareLayerTreeHostImplTest,
// Regular draw causes UpdateTiles.
did_request_prepare_tiles_ = false;
- host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw);
+ host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+ false);
EXPECT_TRUE(did_request_prepare_tiles_);
host_impl_->PrepareTiles();
@@ -11878,7 +11382,7 @@ TEST_F(ResourcelessSoftwareLayerTreeHostImplTest,
resourceless_software_draw = true;
did_request_prepare_tiles_ = false;
host_impl_->OnDraw(draw_transform, new_draw_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
EXPECT_FALSE(did_request_prepare_tiles_);
}
@@ -11934,7 +11438,7 @@ TEST_F(LayerTreeHostImplTest, ExternalViewportAffectsVisibleRects) {
host_impl_->SetExternalTilePriorityConstraints(external_viewport,
external_transform);
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
EXPECT_EQ(gfx::Rect(10, 20), content_layer->visible_layer_rect());
// Clear the external viewport.
@@ -11943,7 +11447,7 @@ TEST_F(LayerTreeHostImplTest, ExternalViewportAffectsVisibleRects) {
external_transform);
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
EXPECT_EQ(gfx::Rect(90, 90), content_layer->visible_layer_rect());
}
@@ -11970,7 +11474,7 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformAffectsVisibleRects) {
// Visible rects should now be shifted and scaled because of the external
// transform.
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
EXPECT_EQ(gfx::Rect(20, 20), content_layer->visible_layer_rect());
// Clear the external transform.
@@ -11979,7 +11483,7 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformAffectsVisibleRects) {
external_transform);
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
EXPECT_EQ(gfx::Rect(50, 50), content_layer->visible_layer_rect());
}
@@ -12018,7 +11522,7 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformAffectsSublayerScaleFactor) {
// Transform node's sublayer scale should include the device transform scale.
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
node = host_impl_->active_tree()->property_trees()->effect_tree.Node(
test_layer->effect_tree_index());
EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(2.f, 2.f));
@@ -12029,7 +11533,7 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformAffectsSublayerScaleFactor) {
external_transform);
host_impl_->OnDraw(external_transform, external_viewport,
- resourceless_software_draw);
+ resourceless_software_draw, false);
node = host_impl_->active_tree()->property_trees()->effect_tree.Node(
test_layer->effect_tree_index());
EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(1.f, 1.f));
@@ -13228,12 +12732,12 @@ class MsaaIsSlowLayerTreeHostImplTest : public LayerTreeHostImplTest {
settings.gpu_rasterization_msaa_sample_count = 4;
auto frame_sink =
FakeLayerTreeFrameSink::Builder()
- .AllContexts(&TestWebGraphicsContext3D::SetMaxSamples,
+ .AllContexts(&viz::TestGLES2Interface::SetMaxSamples,
settings.gpu_rasterization_msaa_sample_count)
- .AllContexts(&TestWebGraphicsContext3D::set_msaa_is_slow,
+ .AllContexts(&viz::TestGLES2Interface::set_msaa_is_slow,
msaa_is_slow)
- .AllContexts(&TestWebGraphicsContext3D::set_gpu_rasterization, true)
- .AllContexts(&TestWebGraphicsContext3D::set_avoid_stencil_buffers,
+ .AllContexts(&viz::TestGLES2Interface::set_gpu_rasterization, true)
+ .AllContexts(&viz::TestGLES2Interface::set_avoid_stencil_buffers,
avoid_stencil_buffers)
.Build();
EXPECT_TRUE(CreateHostImpl(settings, std::move(frame_sink)));
@@ -13289,12 +12793,12 @@ class MsaaCompatibilityLayerTreeHostImplTest : public LayerTreeHostImplTest {
settings.gpu_rasterization_msaa_sample_count = 4;
auto frame_sink =
FakeLayerTreeFrameSink::Builder()
- .AllContexts(&TestWebGraphicsContext3D::SetMaxSamples,
+ .AllContexts(&viz::TestGLES2Interface::SetMaxSamples,
settings.gpu_rasterization_msaa_sample_count)
- .AllContexts(&TestWebGraphicsContext3D::
- set_support_multisample_compatibility,
- support_multisample_compatibility)
- .AllContexts(&TestWebGraphicsContext3D::set_gpu_rasterization, true)
+ .AllContexts(
+ &viz::TestGLES2Interface::set_support_multisample_compatibility,
+ support_multisample_compatibility)
+ .AllContexts(&viz::TestGLES2Interface::set_gpu_rasterization, true)
.Build();
EXPECT_TRUE(CreateHostImpl(settings, std::move(frame_sink)));
}
@@ -13504,14 +13008,14 @@ TEST_F(LayerTreeHostImplTest, RecomputeGpuRasterOnLayerTreeFrameSinkChange) {
AnimationHost::CreateForTesting(ThreadInstance::IMPL), 0, nullptr);
host_impl_->SetVisible(true);
- // InitializeRenderer with a gpu-raster enabled output surface.
+ // InitializeFrameSink with a gpu-raster enabled output surface.
auto gpu_raster_layer_tree_frame_sink = FakeLayerTreeFrameSink::Create3d();
- host_impl_->InitializeRenderer(gpu_raster_layer_tree_frame_sink.get());
+ host_impl_->InitializeFrameSink(gpu_raster_layer_tree_frame_sink.get());
EXPECT_TRUE(host_impl_->use_gpu_rasterization());
// Re-initialize with a software output surface.
layer_tree_frame_sink_ = FakeLayerTreeFrameSink::CreateSoftware();
- host_impl_->InitializeRenderer(layer_tree_frame_sink_.get());
+ host_impl_->InitializeFrameSink(layer_tree_frame_sink_.get());
EXPECT_FALSE(host_impl_->use_gpu_rasterization());
}
@@ -14089,44 +13593,21 @@ TEST_F(LayerTreeHostImplTest, WhiteListedTouchActionTest4) {
WhiteListedTouchActionTestHelper(2.654f, 0.678f);
}
-// Test implementation of a SwapPromise which will always attempt to increment
-// the frame token during WillSwap.
-class FrameTokenAdvancingSwapPromise : public SwapPromise {
- public:
- FrameTokenAdvancingSwapPromise() {}
- ~FrameTokenAdvancingSwapPromise() override {}
-
- void DidActivate() override {}
- void WillSwap(viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator) override {
- frame_token_allocator->GetOrAllocateFrameToken();
- }
- void DidSwap() override {}
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
- return SwapPromise::DidNotSwapAction::BREAK_PROMISE;
- }
- int64_t TraceId() const override { return 42; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FrameTokenAdvancingSwapPromise);
-};
-
// Test implementation of RenderFrameMetadataObserver which can optionally
-// increment the frame token during OnRenderFrameSubmission.
+// request the frame-token to be sent to the embedder during frame submission.
class TestRenderFrameMetadataObserver : public RenderFrameMetadataObserver {
public:
explicit TestRenderFrameMetadataObserver(bool increment_counter)
: increment_counter_(increment_counter) {}
~TestRenderFrameMetadataObserver() override {}
- void BindToCurrentThread(
- FrameTokenAllocator* frame_token_allocator) override {
- frame_token_allocator_ = frame_token_allocator;
- }
- void OnRenderFrameSubmission(RenderFrameMetadata metadata) override {
+ void BindToCurrentThread() override {}
+ void OnRenderFrameSubmission(
+ const RenderFrameMetadata& render_frame_metadata,
+ viz::CompositorFrameMetadata* compositor_frame_metadata) override {
if (increment_counter_)
- frame_token_allocator_->GetOrAllocateFrameToken();
- last_metadata_ = metadata;
+ compositor_frame_metadata->send_frame_token_to_embedder = true;
+ last_metadata_ = render_frame_metadata;
}
const base::Optional<RenderFrameMetadata>& last_metadata() const {
@@ -14134,106 +13615,12 @@ class TestRenderFrameMetadataObserver : public RenderFrameMetadataObserver {
}
private:
- FrameTokenAllocator* frame_token_allocator_;
bool increment_counter_;
base::Optional<RenderFrameMetadata> last_metadata_;
DISALLOW_COPY_AND_ASSIGN(TestRenderFrameMetadataObserver);
};
-// Tests that SwapPromises and RenderFrameMetadataObservers can increment the
-// frame token when frames are being drawn. Furthermore verifies that when there
-// are multiple attempts to increment the frame token during the same draw, that
-// the token only ever increments by one.
-TEST_F(LayerTreeHostImplTest, FrameTokenAllocation) {
- SetupScrollAndContentsLayers(gfx::Size(100, 100));
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->SetViewportSize(gfx::Size(50, 50));
-
- uint32_t expected_frame_token = 0u;
- auto* fake_layer_tree_frame_sink =
- static_cast<FakeLayerTreeFrameSink*>(host_impl_->layer_tree_frame_sink());
-
- // No SwapPromise or RenderFrameMetadataObserver
- {
- DrawFrame();
- const viz::CompositorFrameMetadata& metadata =
- fake_layer_tree_frame_sink->last_sent_frame()->metadata;
- // With no token advancing we should receive the default of 0.
- EXPECT_EQ(expected_frame_token, metadata.frame_token);
- }
-
- // Just a SwapPromise no RenderFrameMetataObsever
- {
- std::vector<std::unique_ptr<SwapPromise>> promises;
- promises.push_back(std::make_unique<FrameTokenAdvancingSwapPromise>());
- host_impl_->active_tree()->PassSwapPromises(std::move(promises));
-
- host_impl_->SetViewportDamage(gfx::Rect(10, 10));
- DrawFrame();
- const viz::CompositorFrameMetadata& metadata =
- fake_layer_tree_frame_sink->last_sent_frame()->metadata;
- // SwapPromise should advance the token count by one.
- EXPECT_EQ(++expected_frame_token, metadata.frame_token);
- }
-
- // Just a RenderFrameMetadataObserver which does not advance the counter.
- {
- host_impl_->SetRenderFrameObserver(
- std::make_unique<TestRenderFrameMetadataObserver>(false));
- host_impl_->SetViewportDamage(gfx::Rect(10, 10));
- DrawFrame();
-
- const viz::CompositorFrameMetadata& metadata =
- fake_layer_tree_frame_sink->last_sent_frame()->metadata;
- // With no token advancing we should receive the default of 0.
- EXPECT_EQ(0u, metadata.frame_token);
- }
-
- // A SwapPromise which advances, and a RenderFrameMetadataObserver which does
- // not advance the counter.
- {
- std::vector<std::unique_ptr<SwapPromise>> promises;
- promises.push_back(std::make_unique<FrameTokenAdvancingSwapPromise>());
- host_impl_->active_tree()->PassSwapPromises(std::move(promises));
-
- host_impl_->SetViewportDamage(gfx::Rect(10, 10));
- DrawFrame();
- const viz::CompositorFrameMetadata& metadata =
- fake_layer_tree_frame_sink->last_sent_frame()->metadata;
- // SwapPromise should advance the token count by one.
- EXPECT_EQ(++expected_frame_token, metadata.frame_token);
- }
-
- // Both a SwapPromise and a RenderFrameMetadataObserver which try to advance
- // the counter.
- {
- std::vector<std::unique_ptr<SwapPromise>> promises;
- promises.push_back(std::make_unique<FrameTokenAdvancingSwapPromise>());
- host_impl_->active_tree()->PassSwapPromises(std::move(promises));
-
- host_impl_->SetRenderFrameObserver(
- std::make_unique<TestRenderFrameMetadataObserver>(true));
- host_impl_->SetViewportDamage(gfx::Rect(10, 10));
- DrawFrame();
- const viz::CompositorFrameMetadata& metadata =
- fake_layer_tree_frame_sink->last_sent_frame()->metadata;
- // Even with both sources trying to advance the frame token, it should
- // only increment by one.
- EXPECT_EQ(++expected_frame_token, metadata.frame_token);
- }
-
- // Just a RenderFrameMetadataObserver which advances the counter
- {
- host_impl_->SetViewportDamage(gfx::Rect(10, 10));
- DrawFrame();
- const viz::CompositorFrameMetadata& metadata =
- fake_layer_tree_frame_sink->last_sent_frame()->metadata;
- // The RenderFrameMetadataObserver should advance the counter by one.
- EXPECT_EQ(++expected_frame_token, metadata.frame_token);
- }
-}
-
TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToRenderFrameMetadata) {
const int root_layer_id = 1;
std::unique_ptr<SolidColorLayerImpl> root =
@@ -14505,5 +13892,51 @@ TEST_F(HitTestRegionListGeneratingLayerTreeHostImplTest, BuildHitTestData) {
hit_test_region_list->regions[0].rect.ToString());
}
+TEST_F(LayerTreeHostImplTest, ImplThreadPhaseUponImplSideInvalidation) {
+ LayerTreeSettings settings = DefaultSettings();
+ CreateHostImpl(settings, CreateLayerTreeFrameSink());
+ // In general invalidation should never be ran outside the impl frame.
+ host_impl_->WillBeginImplFrame(
+ viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1));
+ // Expect no crash because the operation is within an impl frame.
+ host_impl_->InvalidateContentOnImplSide();
+
+ // Once the impl frame is finished the impl thread phase is set to IDLE.
+ host_impl_->DidFinishImplFrame();
+
+ settings.using_synchronous_renderer_compositor = true;
+ CreateHostImpl(settings, CreateLayerTreeFrameSink());
+ // Expect no crash when using synchronous renderer compositor regardless the
+ // impl thread phase.
+ host_impl_->InvalidateContentOnImplSide();
+
+ // Test passes when there is no crash.
+}
+
+TEST_F(LayerTreeHostImplTest, SkipOnDrawDoesNotUpdateDrawParams) {
+ EXPECT_TRUE(CreateHostImpl(DefaultSettings(),
+ FakeLayerTreeFrameSink::CreateSoftware()));
+ LayerImpl* layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ layer->SetDrawsContent(true);
+ gfx::Transform transform;
+ transform.Translate(20, 20);
+ gfx::Rect viewport(0, 0, 50, 50);
+ const bool resourceless_software_draw = false;
+
+ bool skip_draw = false;
+ host_impl_->OnDraw(transform, viewport, resourceless_software_draw,
+ skip_draw);
+ EXPECT_EQ(transform, host_impl_->DrawTransform());
+ EXPECT_EQ(viewport, host_impl_->DeviceViewport());
+
+ skip_draw = true;
+ gfx::Transform new_transform;
+ gfx::Rect new_viewport;
+ host_impl_->OnDraw(new_transform, new_viewport, resourceless_software_draw,
+ skip_draw);
+ EXPECT_EQ(transform, host_impl_->DrawTransform());
+ EXPECT_EQ(viewport, host_impl_->DeviceViewport());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_perftest.cc b/chromium/cc/trees/layer_tree_host_perftest.cc
index 871e1a10a17..fe6ad7870da 100644
--- a/chromium/cc/trees/layer_tree_host_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_perftest.cc
@@ -261,7 +261,7 @@ class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader {
return;
static const gfx::Vector2d delta = gfx::Vector2d(0, 10);
scrollable_->SetScrollOffset(
- gfx::ScrollOffsetWithDelta(scrollable_->scroll_offset(), delta));
+ gfx::ScrollOffsetWithDelta(scrollable_->CurrentScrollOffset(), delta));
}
private:
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
index b251df562ab..841a5eafc9e 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -137,7 +137,13 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, TransformScale) {
base::FilePath(FILE_PATH_LITERAL("spiral_double_scale.png")));
}
-TEST_F(LayerTreeHostScrollbarsPixelTest, HugeTransformScale) {
+// Disabled on TSan due to frequent timeouts. crbug.com/848994
+#if defined(THREAD_SANITIZER)
+#define MAYBE_HugeTransformScale DISABLED_HugeTransformScale
+#else
+#define MAYBE_HugeTransformScale HugeTransformScale
+#endif
+TEST_F(LayerTreeHostScrollbarsPixelTest, MAYBE_HugeTransformScale) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE);
@@ -150,7 +156,8 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, HugeTransformScale) {
background->AddChild(layer);
scoped_refptr<TestInProcessContextProvider> context(
- new TestInProcessContextProvider(/*enable_oop_rasterization=*/false));
+ new TestInProcessContextProvider(/*enable_oop_rasterization=*/false,
+ /*support_locking=*/false));
context->BindToCurrentThread();
int max_texture_size = 0;
context->ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc
index e66bf23fa85..54ef9321ca6 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -67,7 +67,6 @@
#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 "components/viz/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/khronos/GLES2/gl2.h"
@@ -90,6 +89,13 @@ const char kCheckerboardArea[] = "CheckerboardedContentArea";
const char kCheckerboardAreaRatio[] = "CheckerboardedContentAreaRatio";
const char kMissingTiles[] = "NumMissingTiles";
+bool LayerSubtreeHasCopyRequest(Layer* layer) {
+ LayerTreeHost* host = layer->layer_tree_host();
+ int index = layer->effect_tree_index();
+ auto* node = host->property_trees()->effect_tree.Node(index);
+ return node->subtree_has_copy_request;
+}
+
class LayerTreeHostTest : public LayerTreeTest {};
class LayerTreeHostTestHasImplThreadTest : public LayerTreeHostTest {
@@ -210,6 +216,48 @@ class LayerTreeHostTestFrameOrdering : public LayerTreeHostTest {
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestFrameOrdering);
+class LayerTreeHostTestRequestedMainFrame : public LayerTreeHostTest {
+ public:
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void WillBeginMainFrame() override {
+ // Post NextStep() so it happens after the MainFrame completes.
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&LayerTreeHostTestRequestedMainFrame::NextStep,
+ base::Unretained(this)));
+ }
+
+ void NextStep() {
+ // The MainFrame request is cleared once a MainFrame happens.
+ EXPECT_FALSE(layer_tree_host()->RequestedMainFramePending());
+ switch (layer_tree_host()->SourceFrameNumber()) {
+ case 0:
+ ADD_FAILURE()
+ << "Case 0 is the initial commit used to send the test here";
+ FALLTHROUGH;
+ case 1:
+ layer_tree_host()->SetNeedsAnimate();
+ break;
+ case 2:
+ layer_tree_host()->SetNeedsUpdateLayers();
+ break;
+ case 3:
+ layer_tree_host()->SetNeedsCommit();
+ break;
+ case 4:
+ EndTest();
+ return;
+ }
+ // SetNeeds{Animate,UpdateLayers,Commit}() will mean a MainFrame is pending.
+ EXPECT_TRUE(layer_tree_host()->RequestedMainFramePending());
+ }
+
+ void AfterTest() override {}
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestRequestedMainFrame);
+
class LayerTreeHostTestSetNeedsUpdateInsideLayout : public LayerTreeHostTest {
protected:
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
@@ -1274,6 +1322,100 @@ class LayerTreeHostTestEarlyDamageCheckStops : public LayerTreeHostTest {
// multi-threaded compositor.
MULTI_THREAD_TEST_F(LayerTreeHostTestEarlyDamageCheckStops);
+// When settings->enable_early_damage_check is true, verifies that PrepareTiles
+// need not cause a draw when there is no visible damage. Here, a child layer is
+// translated outside of the viewport. After two draws, the early damage check
+// should prevent further draws, but preventing further draws should not prevent
+// PrepareTiles.
+class LayerTreeHostTestPrepareTilesWithoutDraw : public LayerTreeHostTest {
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->using_synchronous_renderer_compositor = true;
+ settings->enable_early_damage_check = true;
+ }
+
+ protected:
+ void SetupTree() override {
+ LayerTreeHostTest::SetupTree();
+ child_layer_ = Layer::Create();
+ layer_tree_host()->root_layer()->AddChild(child_layer_);
+
+ layer_tree_host()->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f,
+ viz::LocalSurfaceId());
+
+ layer_tree_host()->root_layer()->SetBounds(gfx::Size(50, 50));
+ child_layer_->SetBounds(gfx::Size(50, 50));
+
+ // Translate the child layer past the viewport.
+ gfx::Transform translation;
+ translation.Translate(100, 100);
+ child_layer_->SetTransform(translation);
+ child_layer_->SetBounds(gfx::Size(50, 50));
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void DidCommit() override {
+ int frame_number = layer_tree_host()->SourceFrameNumber();
+ if (frame_number > 3) {
+ EndTest();
+ return;
+ }
+
+ // Modify the child layer each frame.
+ float new_opacity = 0.9f / (frame_number + 1);
+ child_layer_->SetOpacity(new_opacity);
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void WillPrepareTilesOnThread(LayerTreeHostImpl* impl) override {
+ if (impl->active_tree()->source_frame_number() >= 0)
+ prepare_tiles_count_++;
+
+ switch (impl->active_tree()->source_frame_number()) {
+ case 0:
+ EXPECT_EQ(1, prepare_tiles_count_);
+ break;
+ case 1:
+ EXPECT_EQ(2, prepare_tiles_count_);
+ break;
+ case 2:
+ EXPECT_EQ(3, prepare_tiles_count_);
+ break;
+ }
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ draw_count_++;
+
+ switch (impl->active_tree()->source_frame_number()) {
+ case 0:
+ // There is actual damage as the layers are set up.
+ EXPECT_EQ(1, draw_count_);
+ break;
+ case 1:
+ // There is no damage, but draw because the early damage check
+ // didn't occur.
+ EXPECT_EQ(2, draw_count_);
+ break;
+ default:
+ // After the first two draws, the early damage check should kick
+ // in and prevent further draws.
+ ADD_FAILURE();
+ }
+ }
+
+ void AfterTest() override { EXPECT_EQ(2, draw_count_); }
+
+ private:
+ scoped_refptr<Layer> child_layer_;
+ int prepare_tiles_count_ = 0;
+ int draw_count_ = 0;
+};
+
+// This behavior is specific to Android WebView, which only uses
+// multi-threaded compositor.
+MULTI_THREAD_TEST_F(LayerTreeHostTestPrepareTilesWithoutDraw);
+
// Verify CanDraw() is false until first commit.
class LayerTreeHostTestCantDrawBeforeCommit : public LayerTreeHostTest {
protected:
@@ -1898,8 +2040,11 @@ class LayerTreeHostTestTransformTreeDamageIsUpdated : public LayerTreeHostTest {
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestTransformTreeDamageIsUpdated);
-class UpdateCountingLayer : public Layer {
+class UpdateCountingLayer : public PictureLayer {
public:
+ explicit UpdateCountingLayer(ContentLayerClient* client)
+ : PictureLayer(client) {}
+
bool Update() override {
update_count_++;
return false;
@@ -1921,9 +2066,9 @@ class LayerTreeHostTestSwitchMaskLayer : public LayerTreeHostTest {
void SetupTree() override {
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(gfx::Size(10, 10));
- child_layer_ = base::MakeRefCounted<UpdateCountingLayer>();
+ child_layer_ = base::MakeRefCounted<UpdateCountingLayer>(&client_);
child_layer_->SetBounds(gfx::Size(10, 10));
- mask_layer_ = base::MakeRefCounted<UpdateCountingLayer>();
+ mask_layer_ = base::MakeRefCounted<UpdateCountingLayer>(&client_);
mask_layer_->SetBounds(gfx::Size(10, 10));
child_layer_->SetMaskLayer(mask_layer_.get());
root->AddChild(child_layer_);
@@ -1970,6 +2115,7 @@ class LayerTreeHostTestSwitchMaskLayer : public LayerTreeHostTest {
void AfterTest() override {}
+ FakeContentLayerClient client_;
scoped_refptr<UpdateCountingLayer> mask_layer_;
scoped_refptr<UpdateCountingLayer> child_layer_;
int index_;
@@ -2414,24 +2560,24 @@ class LayerTreeHostTestRasterColorSpaceChange : public LayerTreeHostTest {
PostSetNeedsCommitToMainThread();
break;
case 2:
- EXPECT_FALSE(child_layer_->NeedsDisplayForTesting());
+ EXPECT_TRUE(child_layer_->update_rect().IsEmpty());
layer_tree_host()->SetRasterColorSpace(space2_);
- EXPECT_TRUE(child_layer_->NeedsDisplayForTesting());
+ EXPECT_FALSE(child_layer_->update_rect().IsEmpty());
break;
case 3:
// The redundant SetRasterColorSpace should cause no commit and no
// damage. Force a commit for the test to continue.
layer_tree_host()->SetRasterColorSpace(space2_);
PostSetNeedsCommitToMainThread();
- EXPECT_FALSE(child_layer_->NeedsDisplayForTesting());
+ EXPECT_TRUE(child_layer_->update_rect().IsEmpty());
break;
case 4:
- EXPECT_FALSE(child_layer_->NeedsDisplayForTesting());
+ EXPECT_TRUE(child_layer_->update_rect().IsEmpty());
layer_tree_host()->SetRasterColorSpace(space1_);
- EXPECT_TRUE(child_layer_->NeedsDisplayForTesting());
+ EXPECT_FALSE(child_layer_->update_rect().IsEmpty());
break;
case 5:
- EXPECT_FALSE(child_layer_->NeedsDisplayForTesting());
+ EXPECT_TRUE(child_layer_->update_rect().IsEmpty());
PostSetNeedsCommitToMainThread();
break;
case 6:
@@ -2932,7 +3078,7 @@ class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest {
const gfx::Vector2dF& elastic_overscroll_delta,
float scale,
float) override {
- gfx::ScrollOffset offset = scroll_layer_->scroll_offset();
+ gfx::ScrollOffset offset = scroll_layer_->CurrentScrollOffset();
scroll_layer_->SetScrollOffset(ScrollOffsetWithDelta(offset, scroll_delta));
layer_tree_host()->SetPageScaleFactorAndLimits(scale, 0.5f, 2.f);
}
@@ -3026,7 +3172,7 @@ class ViewportDeltasAppliedDuringPinch : public LayerTreeHostTest {
EXPECT_EQ(2, scale_delta);
auto* scroll_layer = layer_tree_host()->inner_viewport_scroll_layer();
- EXPECT_EQ(gfx::ScrollOffset(50, 50), scroll_layer->scroll_offset());
+ EXPECT_EQ(gfx::ScrollOffset(50, 50), scroll_layer->CurrentScrollOffset());
EndTest();
}
@@ -3829,12 +3975,12 @@ class OnDrawLayerTreeFrameSink : public viz::TestLayerTreeFrameSink {
invalidate_callback_(std::move(invalidate_callback)) {}
// TestLayerTreeFrameSink overrides.
- void Invalidate() override { invalidate_callback_.Run(); }
+ void Invalidate(bool needs_draw) override { invalidate_callback_.Run(); }
void OnDraw(bool resourceless_software_draw) {
gfx::Transform identity;
gfx::Rect empty_rect;
- client_->OnDraw(identity, empty_rect, resourceless_software_draw);
+ client_->OnDraw(identity, empty_rect, resourceless_software_draw, false);
}
private:
@@ -4005,7 +4151,7 @@ class LayerTreeHostTestUIResource : public LayerTreeHostTest {
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
auto* context = static_cast<viz::TestContextProvider*>(
impl->layer_tree_frame_sink()->context_provider())
- ->TestContext3d();
+ ->TestContextGL();
int frame = impl->active_tree()->source_frame_number();
switch (frame) {
@@ -5324,8 +5470,7 @@ class TestSwapPromise : public SwapPromise {
result_->did_activate_called = true;
}
- void WillSwap(viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator) override {
+ void WillSwap(viz::CompositorFrameMetadata* metadata) override {
base::AutoLock lock(result_->lock);
EXPECT_FALSE(result_->did_swap_called);
EXPECT_FALSE(result_->did_not_swap_called);
@@ -5334,7 +5479,7 @@ class TestSwapPromise : public SwapPromise {
void DidSwap() override {}
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
+ void DidNotSwap(DidNotSwapReason reason) override {
base::AutoLock lock(result_->lock);
EXPECT_FALSE(result_->did_swap_called);
EXPECT_FALSE(result_->did_not_swap_called);
@@ -5342,7 +5487,6 @@ class TestSwapPromise : public SwapPromise {
reason != DidNotSwapReason::SWAP_FAILS);
result_->did_not_swap_called = true;
result_->reason = reason;
- return DidNotSwapAction::BREAK_PROMISE;
}
int64_t TraceId() const override { return 0; }
@@ -6052,16 +6196,16 @@ class LayerTreeHostWithGpuRasterizationTest : public LayerTreeHostTest {
scoped_refptr<viz::RasterContextProvider> ignored_worker_context_provider)
override {
auto context_provider = viz::TestContextProvider::Create();
- context_provider->UnboundTestContext3d()->SetMaxSamples(4);
- context_provider->UnboundTestContext3d()
- ->set_support_multisample_compatibility(false);
- context_provider->UnboundTestContext3d()->set_gpu_rasterization(true);
+ viz::TestGLES2Interface* gl = context_provider->UnboundTestContextGL();
+ gl->SetMaxSamples(4);
+ gl->set_support_multisample_compatibility(false);
+ gl->set_gpu_rasterization(true);
auto worker_context_provider = viz::TestContextProvider::CreateWorker();
- worker_context_provider->UnboundTestContext3d()->SetMaxSamples(4);
- worker_context_provider->UnboundTestContext3d()
- ->set_support_multisample_compatibility(false);
- worker_context_provider->UnboundTestContext3d()->set_gpu_rasterization(
- true);
+ viz::TestGLES2Interface* worker_gl =
+ worker_context_provider->UnboundTestContextGL();
+ worker_gl->SetMaxSamples(4);
+ worker_gl->set_support_multisample_compatibility(false);
+ worker_gl->set_gpu_rasterization(true);
return LayerTreeHostTest::CreateLayerTreeFrameSink(
renderer_settings, refresh_rate, std::move(context_provider),
std::move(worker_context_provider));
@@ -6907,11 +7051,11 @@ class LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy
override {
scoped_refptr<viz::TestContextProvider> display_context_provider =
viz::TestContextProvider::Create();
- viz::TestWebGraphicsContext3D* context3d =
- display_context_provider->UnboundTestContext3d();
- context3d->set_support_sync_query(true);
+ viz::TestGLES2Interface* gl =
+ display_context_provider->UnboundTestContextGL();
+ gl->set_support_sync_query(true);
#if defined(OS_MACOSX)
- context3d->set_support_texture_rectangle(true);
+ gl->set_support_texture_rectangle(true);
#endif
display_context_provider->BindToCurrentThread();
return LayerTreeTest::CreateDisplayOutputSurfaceOnThread(
@@ -7353,7 +7497,7 @@ class LayerTreeHostTestUpdateCopyRequests : public LayerTreeHostTest {
void WillCommit() override {
switch (layer_tree_host()->SourceFrameNumber()) {
case 1:
- EXPECT_TRUE(root->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(LayerSubtreeHasCopyRequest(root.get()));
break;
}
}
@@ -7376,7 +7520,7 @@ class LayerTreeHostTestUpdateCopyRequests : public LayerTreeHostTest {
child->SetTransform(transform);
break;
case 3:
- EXPECT_FALSE(root->has_copy_requests_in_target_subtree());
+ EXPECT_FALSE(LayerSubtreeHasCopyRequest(root.get()));
EndTest();
break;
}
@@ -7523,7 +7667,7 @@ class LayerTreeHostTestPresentationTimeRequest : public LayerTreeHostTest {
void DisplayReceivedCompositorFrameOnThread(
const viz::CompositorFrame& frame) override {
- EXPECT_NE(0u, frame.metadata.presentation_token);
+ EXPECT_TRUE(frame.metadata.request_presentation_feedback);
EndTest();
}
@@ -7531,6 +7675,55 @@ class LayerTreeHostTestPresentationTimeRequest : public LayerTreeHostTest {
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPresentationTimeRequest);
+// A SwapPromise that turns on |request_presentation_feedback| during
+// WillSwap().
+class RequestPresentationFeedbackSwapPromise : public SwapPromise {
+ public:
+ RequestPresentationFeedbackSwapPromise() = default;
+ ~RequestPresentationFeedbackSwapPromise() override = default;
+
+ // SwapPromise:
+ void DidActivate() override {}
+ void WillSwap(viz::CompositorFrameMetadata* metadata) override {
+ metadata->request_presentation_feedback = true;
+ }
+ void DidSwap() override {}
+ void DidNotSwap(DidNotSwapReason reason) override {}
+ int64_t TraceId() const override { return 0; }
+};
+
+// Tests that a presentation-token can be requested during swap.
+class LayerTreeHostTestPresentationTimeRequestDuringSwap
+ : public LayerTreeHostTest {
+ protected:
+ void BeginTest() override {
+ layer_tree_host()->QueueSwapPromise(
+ std::make_unique<RequestPresentationFeedbackSwapPromise>());
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ EXPECT_TRUE(frame.metadata.request_presentation_feedback);
+ frame_token_ = frame.metadata.frame_token;
+ }
+
+ void DidReceivePresentationTimeOnThread(
+ LayerTreeHostImpl* host_impl,
+ uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback) override {
+ EXPECT_EQ(frame_token_, frame_token);
+ EndTest();
+ }
+
+ void AfterTest() override { ASSERT_GT(frame_token_, 0u); }
+
+ private:
+ uint32_t frame_token_ = 0;
+};
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostTestPresentationTimeRequestDuringSwap);
+
// Makes sure that viz::LocalSurfaceId is propagated to the LayerTreeFrameSink.
class LayerTreeHostTestLocalSurfaceId : public LayerTreeHostTest {
protected:
@@ -7565,6 +7758,48 @@ class LayerTreeHostTestLocalSurfaceId : public LayerTreeHostTest {
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLocalSurfaceId);
+// Makes sure that LayerTreeHost does not pick up changes to
+// viz::LocalSurfaceIds that only involve the child sequence number.
+class LayerTreeHostTestLocalSurfaceIdSkipChildNum : public LayerTreeHostTest {
+ protected:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->enable_surface_synchronization = true;
+ }
+
+ void BeginTest() override {
+ expected_local_surface_id_ = allocator_.GetCurrentLocalSurfaceId();
+ EXPECT_TRUE(child_allocator_.UpdateFromParent(expected_local_surface_id_));
+ child_local_surface_id_ = child_allocator_.GenerateId();
+ EXPECT_NE(expected_local_surface_id_, child_local_surface_id_);
+ PostSetLocalSurfaceIdToMainThread(expected_local_surface_id_);
+ PostSetLocalSurfaceIdToMainThread(child_local_surface_id_);
+ }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
+ // We should not be picking up the newer |child_local_surface_id_|.
+ EXPECT_EQ(expected_local_surface_id_,
+ host_impl->active_tree()->local_surface_id_from_parent());
+ return draw_result;
+ }
+
+ void DisplayReceivedLocalSurfaceIdOnThread(
+ const viz::LocalSurfaceId& local_surface_id) override {
+ EXPECT_EQ(expected_local_surface_id_, local_surface_id);
+ EndTest();
+ }
+
+ void AfterTest() override {}
+
+ viz::LocalSurfaceId expected_local_surface_id_;
+ viz::LocalSurfaceId child_local_surface_id_;
+ viz::ParentLocalSurfaceIdAllocator allocator_;
+ viz::ChildLocalSurfaceIdAllocator child_allocator_;
+};
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLocalSurfaceIdSkipChildNum);
+
// Makes sure that viz::LocalSurfaceId allocation requests propagate all the way
// to LayerTreeFrameSink.
class LayerTreeHostTestRequestNewLocalSurfaceId : public LayerTreeHostTest {
@@ -7753,15 +7988,32 @@ class LayerTreeHostTestSubmitFrameResources : public LayerTreeHostTest {
viz::RenderPass* child_pass =
AddRenderPass(&frame->render_passes, 2, gfx::Rect(3, 3, 10, 10),
gfx::Transform(), FilterOperations());
- AddOneOfEveryQuadType(child_pass, host_impl->resource_provider(), 0);
+ std::vector<viz::ResourceId> child_resources =
+ AddOneOfEveryQuadType(child_pass, host_impl->resource_provider(), 0);
viz::RenderPass* pass =
AddRenderPass(&frame->render_passes, 1, gfx::Rect(3, 3, 10, 10),
gfx::Transform(), FilterOperations());
- AddOneOfEveryQuadType(pass, host_impl->resource_provider(), child_pass->id);
+ std::vector<viz::ResourceId> root_resources = AddOneOfEveryQuadType(
+ pass, host_impl->resource_provider(), child_pass->id);
+
+ auto append = [](std::vector<viz::ResourceId>* to,
+ std::vector<viz::ResourceId> from) {
+ to->insert(to->end(), from.begin(), from.end());
+ };
+ append(&resources_, child_resources);
+ append(&resources_, root_resources);
+
return draw_result;
}
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ // The resources have been submitted to the display compositor by now, we
+ // can remove them from cc now, so that they are not leaked.
+ for (viz::ResourceId id : resources_)
+ host_impl->resource_provider()->RemoveImportedResource(id);
+ }
+
void DisplayReceivedCompositorFrameOnThread(
const viz::CompositorFrame& frame) override {
EXPECT_EQ(2u, frame.render_pass_list.size());
@@ -7775,6 +8027,8 @@ class LayerTreeHostTestSubmitFrameResources : public LayerTreeHostTest {
}
void AfterTest() override {}
+
+ std::vector<viz::ResourceId> resources_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSubmitFrameResources);
@@ -7829,10 +8083,8 @@ class LayerTreeHostTestBeginFrameAcks : public LayerTreeHostTest {
return;
compositor_frame_submitted_ = true;
- EXPECT_EQ(
- viz::BeginFrameAck(current_begin_frame_args_.source_id,
- current_begin_frame_args_.sequence_number, true),
- frame.metadata.begin_frame_ack);
+ EXPECT_EQ(viz::BeginFrameAck(current_begin_frame_args_, true),
+ frame.metadata.begin_frame_ack);
}
void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
@@ -7842,10 +8094,8 @@ class LayerTreeHostTestBeginFrameAcks : public LayerTreeHostTest {
EXPECT_TRUE(frame_data_);
EXPECT_TRUE(compositor_frame_submitted_);
- EXPECT_EQ(
- viz::BeginFrameAck(current_begin_frame_args_.source_id,
- current_begin_frame_args_.sequence_number, true),
- frame_data_->begin_frame_ack);
+ EXPECT_EQ(viz::BeginFrameAck(current_begin_frame_args_, true),
+ frame_data_->begin_frame_ack);
EndTest();
}
@@ -8211,6 +8461,29 @@ class LayerTreeHostTestImageAnimationSynchronousScheduling
MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimationSynchronousScheduling);
+class LayerTreeHostTestImageAnimationSynchronousSchedulingSoftwareDraw
+ : public LayerTreeHostTestImageAnimationSynchronousScheduling {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ LayerTreeHostTestImageAnimationSynchronousScheduling::InitializeSettings(
+ settings);
+ use_software_renderer_ = true;
+ }
+
+ void AfterTest() override {
+ LayerTreeHostTestImageAnimationSynchronousScheduling::AfterTest();
+ // 3 frames decoded twice, once during tile raster and once during raster
+ // for PictureDrawQuad.
+ for (size_t i = 0u; i < 3u; ++i) {
+ EXPECT_EQ(generator_->frames_decoded().find(i)->second, 2);
+ }
+ }
+};
+
+// TODO(crbug.com/851231): Disabled this test due to flakiness.
+// MULTI_THREAD_TEST_F(
+// LayerTreeHostTestImageAnimationSynchronousSchedulingSoftwareDraw);
+
class LayerTreeHostTestImageDecodingHints : public LayerTreeHostTest {
public:
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 0a1a2b73fc7..0b935c7adf9 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
@@ -29,6 +29,7 @@
#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/transform_node.h"
+#include "components/viz/common/quads/compositor_frame.h"
namespace cc {
namespace {
@@ -820,10 +821,10 @@ class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated
break;
}
default:
- EXPECT_GE(scroll_layer_->scroll_offset().x(), 10);
- EXPECT_GE(scroll_layer_->scroll_offset().y(), 20);
- if (scroll_layer_->scroll_offset().x() > 10 &&
- scroll_layer_->scroll_offset().y() > 20)
+ EXPECT_GE(scroll_layer_->CurrentScrollOffset().x(), 10);
+ EXPECT_GE(scroll_layer_->CurrentScrollOffset().y(), 20);
+ if (scroll_layer_->CurrentScrollOffset().x() > 10 &&
+ scroll_layer_->CurrentScrollOffset().y() > 20)
EndTest();
}
}
@@ -1007,6 +1008,81 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted);
+// Tests that presentation-time requested from the main-thread is attached to
+// the correct frame (i.e. activation needs to happen before the
+// presentation-request is attached to the frame).
+class LayerTreeHostPresentationDuringAnimation
+ : public LayerTreeHostAnimationTest {
+ public:
+ void SetupTree() override {
+ LayerTreeHostAnimationTest::SetupTree();
+
+ scroll_layer_ = FakePictureLayer::Create(&client_);
+ scroll_layer_->SetScrollable(gfx::Size(100, 100));
+ scroll_layer_->SetBounds(gfx::Size(10000, 10000));
+ client_.set_bounds(scroll_layer_->bounds());
+ scroll_layer_->SetScrollOffset(gfx::ScrollOffset(100.0, 200.0));
+ layer_tree_host()->root_layer()->AddChild(scroll_layer_);
+
+ std::unique_ptr<ScrollOffsetAnimationCurve> curve(
+ ScrollOffsetAnimationCurve::Create(
+ gfx::ScrollOffset(6500.f, 7500.f),
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
+ std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
+ std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ keyframe_model->set_needs_synchronized_start_time(true);
+
+ AttachAnimationsToTimeline();
+ animation_child_->AttachElement(scroll_layer_->element_id());
+ animation_child_->AddKeyframeModel(std::move(keyframe_model));
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void BeginMainFrame(const viz::BeginFrameArgs& args) override {
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->active_tree()->source_frame_number() == 1) {
+ request_token_ = host_impl->next_frame_token();
+ layer_tree_host()->RequestPresentationTimeForNextFrame(base::BindOnce(
+ &LayerTreeHostPresentationDuringAnimation::OnPresentation,
+ base::Unretained(this)));
+ host_impl->BlockNotifyReadyToActivateForTesting(true);
+ }
+ }
+
+ void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
+ const viz::BeginFrameArgs& args) override {
+ if (host_impl->next_frame_token() >= 5)
+ host_impl->BlockNotifyReadyToActivateForTesting(false);
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ if (frame.metadata.request_presentation_feedback)
+ received_token_ = frame.metadata.frame_token;
+ }
+
+ void AfterTest() override {
+ EXPECT_GT(request_token_, 0u);
+ EXPECT_GT(received_token_, request_token_);
+ EXPECT_GE(received_token_, 5u);
+ }
+
+ private:
+ void OnPresentation(const gfx::PresentationFeedback& feedback) { EndTest(); }
+
+ FakeContentLayerClient client_;
+ scoped_refptr<FakePictureLayer> scroll_layer_;
+ uint32_t request_token_ = 0;
+ uint32_t received_token_ = 0;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostPresentationDuringAnimation);
+
// Verifies that when the main thread removes a scroll animation and sets a new
// scroll position, the active tree takes on exactly this new scroll position
// after activation, and the main thread doesn't receive a spurious scroll
@@ -1046,12 +1122,12 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationRemoval
void BeginMainFrame(const viz::BeginFrameArgs& args) override {
switch (layer_tree_host()->SourceFrameNumber()) {
case 0:
- EXPECT_EQ(scroll_layer_->scroll_offset().x(), 100);
- EXPECT_EQ(scroll_layer_->scroll_offset().y(), 200);
+ EXPECT_EQ(scroll_layer_->CurrentScrollOffset().x(), 100);
+ EXPECT_EQ(scroll_layer_->CurrentScrollOffset().y(), 200);
break;
case 1: {
- EXPECT_GE(scroll_layer_->scroll_offset().x(), 100);
- EXPECT_GE(scroll_layer_->scroll_offset().y(), 200);
+ EXPECT_GE(scroll_layer_->CurrentScrollOffset().x(), 100);
+ EXPECT_GE(scroll_layer_->CurrentScrollOffset().y(), 200);
KeyframeModel* keyframe_model =
animation_child_->GetKeyframeModel(TargetProperty::SCROLL_OFFSET);
animation_child_->RemoveKeyframeModel(keyframe_model->id());
@@ -1059,7 +1135,7 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationRemoval
break;
}
default:
- EXPECT_EQ(final_postion_, scroll_layer_->scroll_offset());
+ EXPECT_EQ(final_postion_, scroll_layer_->CurrentScrollOffset());
}
}
@@ -1092,7 +1168,7 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationRemoval
}
void AfterTest() override {
- EXPECT_EQ(final_postion_, scroll_layer_->scroll_offset());
+ EXPECT_EQ(final_postion_, scroll_layer_->CurrentScrollOffset());
}
private:
@@ -1220,9 +1296,12 @@ class LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers
EXPECT_EQ(KeyframeModel::RUNNING, child_keyframe_model->run_state());
EXPECT_EQ(root_keyframe_model->start_time(),
child_keyframe_model->start_time());
- animation_impl->AbortKeyframeModels(TargetProperty::OPACITY, false);
- animation_impl->AbortKeyframeModels(TargetProperty::TRANSFORM, false);
- animation_child_impl->AbortKeyframeModels(TargetProperty::OPACITY, false);
+ animation_impl->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY,
+ false);
+ animation_impl->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM,
+ false);
+ animation_child_impl->AbortKeyframeModelsWithProperty(
+ TargetProperty::OPACITY, false);
EndTest();
}
@@ -1300,7 +1379,8 @@ class LayerTreeHostAnimationTestPendingTreeAnimatesFirstCommit
// And the sync tree layer should know it is animating.
EXPECT_TRUE(child->screen_space_transform_is_animating());
- animation_impl->AbortKeyframeModels(TargetProperty::TRANSFORM, false);
+ animation_impl->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM,
+ false);
EndTest();
}
diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc
index f3ec645e85a..a57153ed21b 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_context.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc
@@ -22,7 +22,6 @@
#include "cc/test/fake_painted_scrollbar_layer.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/fake_picture_layer_impl.h"
-#include "cc/test/fake_resource_provider.h"
#include "cc/test/fake_scoped_ui_resource.h"
#include "cc/test/fake_scrollbar.h"
#include "cc/test/fake_video_frame_provider.h"
@@ -32,12 +31,13 @@
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
+#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/resources/single_release_callback.h"
+#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 "components/viz/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "media/base/media.h"
@@ -886,8 +886,7 @@ class LayerTreeHostContextTestDontUseLostResources
CHECK_EQ(result, gpu::ContextResult::kSuccess);
shared_bitmap_manager_ = std::make_unique<viz::TestSharedBitmapManager>();
child_resource_provider_ =
- FakeResourceProvider::CreateLayerTreeResourceProvider(
- child_context_provider_.get());
+ std::make_unique<viz::ClientResourceProvider>(true);
}
static void EmptyReleaseCallback(const gpu::SyncToken& sync_token,
@@ -896,8 +895,7 @@ class LayerTreeHostContextTestDontUseLostResources
void SetupTree() override {
gpu::gles2::GLES2Interface* gl = child_context_provider_->ContextGL();
- gpu::Mailbox mailbox;
- gl->GenMailboxCHROMIUM(mailbox.name);
+ gpu::Mailbox mailbox = gpu::Mailbox::Generate();
gpu::SyncToken sync_token;
gl->GenSyncTokenCHROMIUM(sync_token.GetData());
@@ -1042,7 +1040,7 @@ class LayerTreeHostContextTestDontUseLostResources
scoped_refptr<viz::TestContextProvider> child_context_provider_;
std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<LayerTreeResourceProvider> child_resource_provider_;
+ std::unique_ptr<viz::ClientResourceProvider> child_resource_provider_;
scoped_refptr<VideoFrame> color_video_frame_;
scoped_refptr<VideoFrame> hw_video_frame_;
@@ -1555,6 +1553,176 @@ class UIResourceLostEviction : public UIResourceLostTestSimple {
SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
+class UIResourceFreedIfLostWhileExported : public LayerTreeHostContextTest {
+ protected:
+ void BeginTest() override {
+ // Make 1 UIResource, post it to the compositor thread, where it will be
+ // uploaded.
+ ui_resource_ =
+ FakeScopedUIResource::Create(layer_tree_host()->GetUIResourceManager());
+ EXPECT_NE(0, ui_resource_->id());
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
+ switch (impl->active_tree()->source_frame_number()) {
+ case 0:
+ // The UIResource has been created and a gpu resource made for it.
+ EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_EQ(1u, gl_->NumTextures());
+ // Lose the LayerTreeFrameSink connection. The UI resource should
+ // be replaced and the old texture should be destroyed.
+ impl->DidLoseLayerTreeFrameSink();
+ break;
+ case 1:
+ // The UIResource has been recreated, the old texture is not kept
+ // around.
+ EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_EQ(1u, gl_->NumTextures());
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &UIResourceFreedIfLostWhileExported::DeleteAndEndTest,
+ base::Unretained(this)));
+ }
+ }
+
+ void DeleteAndEndTest() {
+ ui_resource_->DeleteResource();
+ EndTest();
+ }
+
+ void AfterTest() override {}
+
+ std::unique_ptr<FakeScopedUIResource> ui_resource_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceFreedIfLostWhileExported);
+
+class TileResourceFreedIfLostWhileExported : public LayerTreeHostContextTest {
+ protected:
+ void SetupTree() override {
+ PaintFlags flags;
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_refptr<FakePictureLayer> picture_layer =
+ FakePictureLayer::Create(&client_);
+ picture_layer->SetBounds(gfx::Size(10, 20));
+ client_.set_bounds(picture_layer->bounds());
+ layer_tree_host()->SetRootLayer(std::move(picture_layer));
+
+ LayerTreeTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ switch (impl->active_tree()->source_frame_number()) {
+ case 0:
+ // The PicturLayer has a texture for a tile, that has been exported to
+ // the display compositor now.
+ EXPECT_EQ(1u, impl->resource_provider()->num_resources_for_testing());
+ EXPECT_EQ(1u, impl->resource_pool()->resource_count());
+ // Shows that the tile texture is allocated with the current context.
+ num_textures_ = gl_->NumTextures();
+ EXPECT_GT(num_textures_, 0u);
+
+ // Lose the LayerTreeFrameSink connection. The tile resource should
+ // be replaced and the old texture should be destroyed.
+ LoseContext();
+ break;
+ case 1:
+ // The tile has been recreated, the old texture is not kept around in
+ // the pool indefinitely. It can be dropped as soon as the context is
+ // known to be lost.
+ EXPECT_EQ(1u, impl->resource_provider()->num_resources_for_testing());
+ EXPECT_EQ(1u, impl->resource_pool()->resource_count());
+ // Shows that the replacement tile texture is re-allocated with the
+ // current context, not just the previous one.
+ EXPECT_EQ(num_textures_, gl_->NumTextures());
+ EndTest();
+ }
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+ size_t num_textures_ = 0;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(TileResourceFreedIfLostWhileExported);
+
+class SoftwareTileResourceFreedIfLostWhileExported : public LayerTreeTest {
+ protected:
+ std::unique_ptr<viz::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 {
+ // Induce software compositing in cc.
+ return LayerTreeTest::CreateLayerTreeFrameSink(
+ renderer_settings, refresh_rate, nullptr, nullptr);
+ }
+
+ std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread(
+ scoped_refptr<viz::ContextProvider> compositor_context_provider)
+ override {
+ // Induce software compositing in the display compositor.
+ return viz::FakeOutputSurface::CreateSoftware(
+ std::make_unique<viz::SoftwareOutputDevice>());
+ }
+
+ void SetupTree() override {
+ PaintFlags flags;
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_refptr<FakePictureLayer> picture_layer =
+ FakePictureLayer::Create(&client_);
+ picture_layer->SetBounds(gfx::Size(10, 20));
+ client_.set_bounds(picture_layer->bounds());
+ layer_tree_host()->SetRootLayer(std::move(picture_layer));
+
+ LayerTreeTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ switch (impl->active_tree()->source_frame_number()) {
+ case 0: {
+ // The PicturLayer has a bitmap for a tile, that has been exported to
+ // the display compositor now.
+ EXPECT_EQ(1u, impl->resource_provider()->num_resources_for_testing());
+ EXPECT_EQ(1u, impl->resource_pool()->resource_count());
+
+ impl->DidLoseLayerTreeFrameSink();
+ break;
+ }
+ case 1: {
+ // The tile did not need to be recreated, the same bitmap/resource
+ // should be used for it.
+ EXPECT_EQ(1u, impl->resource_provider()->num_resources_for_testing());
+ EXPECT_EQ(1u, impl->resource_pool()->resource_count());
+
+ // TODO(danakj): It'd be possible to not destroy and recreate the
+ // software bitmap, however for simplicity we do the same for software
+ // and for gpu paths. If we didn't destroy it we could see the same
+ // bitmap on PictureLayerImpl's tile.
+
+ EndTest();
+ }
+ }
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+ viz::ResourceId exported_resource_id_ = 0;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTileResourceFreedIfLostWhileExported);
+
class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
: public LayerTreeHostContextTest {
protected:
diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
index fcc95241448..83daa78f332 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -16,8 +16,8 @@
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/service/display/direct_renderer.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 "components/viz/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
namespace cc {
@@ -855,7 +855,7 @@ class LayerTreeHostCopyRequestTestDeleteTexture
// releasing the copy output request should cause the texture in the request
// to be destroyed by the compositor, so we should have 1 less by now.
EXPECT_EQ(num_textures_after_readback_ - 1,
- display_context_provider_->TestContext3d()->NumTextures());
+ display_context_provider_->TestContextGL()->NumTextures());
// Drop the reference to the context provider on the compositor thread.
display_context_provider_ = nullptr;
@@ -869,7 +869,7 @@ class LayerTreeHostCopyRequestTestDeleteTexture
// been allocated.
EXPECT_FALSE(result_);
num_textures_without_readback_ =
- display_context_provider_->TestContext3d()->NumTextures();
+ display_context_provider_->TestContextGL()->NumTextures();
// Request a copy of the layer. This will use another texture.
MainThreadTaskRunner()->PostTask(
@@ -886,7 +886,7 @@ class LayerTreeHostCopyRequestTestDeleteTexture
case 2:
// We did a readback, so there will be a readback texture around now.
num_textures_after_readback_ =
- display_context_provider_->TestContext3d()->NumTextures();
+ display_context_provider_->TestContextGL()->NumTextures();
EXPECT_LT(num_textures_without_readback_, num_textures_after_readback_);
// Now destroy the CopyOutputResult, releasing the texture inside back
@@ -981,14 +981,14 @@ class LayerTreeHostCopyRequestTestCountTextures
// The first frame has been drawn, so textures for drawing have been
// allocated.
num_textures_without_readback_ =
- display_context_provider_->TestContext3d()->NumTextures();
+ display_context_provider_->TestContextGL()->NumTextures();
break;
case 1:
// We did a readback, so there will be a readback texture around now.
num_textures_with_readback_ =
- display_context_provider_->TestContext3d()->NumTextures();
+ display_context_provider_->TestContextGL()->NumTextures();
waited_sync_token_after_readback_ =
- display_context_provider_->TestContext3d()
+ display_context_provider_->TestContextGL()
->last_waited_sync_token();
// End the test after main thread has a chance to hear about the
diff --git a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
index d979e0b46ea..41e9c4c0283 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
@@ -152,7 +152,7 @@ class LayerTreeHostOcclusionTestDrawPropertiesOnMask
make_surface_bigger->SetIsDrawable(true);
child_->AddChild(make_surface_bigger);
- scoped_refptr<Layer> mask = PictureLayer::Create(&client_);
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client_);
mask->SetBounds(gfx::Size(30, 40));
mask->SetIsDrawable(true);
child_->SetMaskLayer(mask.get());
@@ -225,7 +225,7 @@ class LayerTreeHostOcclusionTestDrawPropertiesOnScaledMask
grand_child->SetIsDrawable(true);
child_->AddChild(grand_child);
- scoped_refptr<Layer> mask = PictureLayer::Create(&client_);
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client_);
mask->SetBounds(gfx::Size(30, 40));
mask->SetIsDrawable(true);
child_->SetMaskLayer(mask.get());
diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
index dc45563a2c7..d5fa8c48b57 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -108,11 +108,11 @@ class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest {
LayerTreeHostClient::VisualStateUpdate requested_update) override {
Layer* scroll_layer = layer_tree_host()->outer_viewport_scroll_layer();
if (!layer_tree_host()->SourceFrameNumber()) {
- EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->CurrentScrollOffset());
} else {
- EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(initial_scroll_,
- scroll_amount_),
- scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(
+ gfx::ScrollOffsetWithDelta(initial_scroll_, scroll_amount_),
+ scroll_layer->CurrentScrollOffset());
// Pretend like Javascript updated the scroll position itself.
scroll_layer->SetScrollOffset(second_scroll_);
@@ -180,14 +180,13 @@ class LayerTreeHostScrollTestScrollMultipleRedraw
void BeginCommitOnThread(LayerTreeHostImpl* impl) override {
switch (layer_tree_host()->SourceFrameNumber()) {
case 0:
- EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer_->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer_->CurrentScrollOffset());
break;
case 1:
case 2:
- EXPECT_VECTOR_EQ(
- gfx::ScrollOffsetWithDelta(initial_scroll_,
- scroll_amount_ + scroll_amount_),
- scroll_layer_->scroll_offset());
+ EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(
+ initial_scroll_, scroll_amount_ + scroll_amount_),
+ scroll_layer_->CurrentScrollOffset());
break;
}
}
@@ -214,15 +213,14 @@ class LayerTreeHostScrollTestScrollMultipleRedraw
EXPECT_VECTOR_EQ(scroll_amount_ + scroll_amount_,
ScrollDelta(scroll_layer));
- EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer_->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer_->CurrentScrollOffset());
PostSetNeedsCommitToMainThread();
} else if (impl->active_tree()->source_frame_number() == 1) {
// Third or later draw after second commit.
EXPECT_GE(impl->SourceAnimationFrameNumberForTesting(), 3u);
- EXPECT_VECTOR_EQ(
- gfx::ScrollOffsetWithDelta(initial_scroll_,
- scroll_amount_ + scroll_amount_),
- scroll_layer_->scroll_offset());
+ EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(
+ initial_scroll_, scroll_amount_ + scroll_amount_),
+ scroll_layer_->CurrentScrollOffset());
EndTest();
}
}
@@ -284,7 +282,8 @@ class LayerTreeHostScrollTestScrollAbortedCommit
// This will not be aborted because of the initial prop changes.
EXPECT_EQ(0, num_impl_scrolls_);
EXPECT_EQ(0, layer_tree_host()->SourceFrameNumber());
- EXPECT_VECTOR_EQ(initial_scroll_, root_scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_,
+ root_scroll_layer->CurrentScrollOffset());
EXPECT_EQ(1.f, layer_tree_host()->page_scale_factor());
break;
case 2:
@@ -294,7 +293,7 @@ class LayerTreeHostScrollTestScrollAbortedCommit
EXPECT_EQ(1, layer_tree_host()->SourceFrameNumber());
EXPECT_VECTOR_EQ(
gfx::ScrollOffsetWithDelta(initial_scroll_, impl_scroll_),
- root_scroll_layer->scroll_offset());
+ root_scroll_layer->CurrentScrollOffset());
EXPECT_EQ(impl_scale_, layer_tree_host()->page_scale_factor());
PostSetNeedsRedrawToMainThread();
break;
@@ -303,14 +302,13 @@ class LayerTreeHostScrollTestScrollAbortedCommit
EXPECT_EQ(2, num_impl_scrolls_);
// The source frame number still increases even with the abort.
EXPECT_EQ(2, layer_tree_host()->SourceFrameNumber());
- EXPECT_VECTOR_EQ(
- gfx::ScrollOffsetWithDelta(initial_scroll_,
- impl_scroll_ + impl_scroll_),
- root_scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(
+ initial_scroll_, impl_scroll_ + impl_scroll_),
+ root_scroll_layer->CurrentScrollOffset());
EXPECT_EQ(impl_scale_ * impl_scale_,
layer_tree_host()->page_scale_factor());
root_scroll_layer->SetScrollOffset(gfx::ScrollOffsetWithDelta(
- root_scroll_layer->scroll_offset(), second_main_scroll_));
+ root_scroll_layer->CurrentScrollOffset(), second_main_scroll_));
break;
case 4:
// This commit will also be aborted.
@@ -319,7 +317,7 @@ class LayerTreeHostScrollTestScrollAbortedCommit
gfx::Vector2dF delta =
impl_scroll_ + impl_scroll_ + impl_scroll_ + second_main_scroll_;
EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(initial_scroll_, delta),
- root_scroll_layer->scroll_offset());
+ root_scroll_layer->CurrentScrollOffset());
// End the test by drawing to verify this commit is also aborted.
PostSetNeedsRedrawToMainThread();
@@ -635,7 +633,7 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest {
}
void DidScroll(const gfx::ScrollOffset& offset, const ElementId& element_id) {
- final_scroll_offset_ = expected_scroll_layer_->scroll_offset();
+ final_scroll_offset_ = expected_scroll_layer_->CurrentScrollOffset();
EXPECT_VECTOR_EQ(offset, final_scroll_offset_);
EXPECT_EQ(element_id, expected_scroll_layer_->element_id());
}
@@ -647,25 +645,25 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest {
void UpdateLayerTreeHost(
LayerTreeHostClient::VisualStateUpdate requested_update) override {
EXPECT_VECTOR_EQ(gfx::Vector2d(),
- expected_no_scroll_layer_->scroll_offset());
+ expected_no_scroll_layer_->CurrentScrollOffset());
switch (layer_tree_host()->SourceFrameNumber()) {
case 0:
EXPECT_VECTOR_EQ(initial_offset_,
- expected_scroll_layer_->scroll_offset());
+ expected_scroll_layer_->CurrentScrollOffset());
break;
case 1:
EXPECT_VECTOR_EQ(
gfx::ScrollOffsetWithDelta(initial_offset_, scroll_amount_),
- expected_scroll_layer_->scroll_offset());
+ expected_scroll_layer_->CurrentScrollOffset());
// Pretend like Javascript updated the scroll position itself.
expected_scroll_layer_->SetScrollOffset(javascript_scroll_);
break;
case 2:
- EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(javascript_scroll_,
- scroll_amount_),
- expected_scroll_layer_->scroll_offset());
+ EXPECT_VECTOR_EQ(
+ gfx::ScrollOffsetWithDelta(javascript_scroll_, scroll_amount_),
+ expected_scroll_layer_->CurrentScrollOffset());
break;
}
}
@@ -852,10 +850,10 @@ class LayerTreeHostScrollTestSimple : public LayerTreeHostScrollTest {
LayerTreeHostClient::VisualStateUpdate requested_update) override {
Layer* scroll_layer = layer_tree_host()->outer_viewport_scroll_layer();
if (!layer_tree_host()->SourceFrameNumber()) {
- EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->CurrentScrollOffset());
} else {
EXPECT_VECTOR_EQ(
- scroll_layer->scroll_offset(),
+ scroll_layer->CurrentScrollOffset(),
gfx::ScrollOffsetWithDelta(initial_scroll_, impl_thread_scroll1_));
// Pretend like Javascript updated the scroll position itself with a
@@ -1301,12 +1299,6 @@ class ThreadCheckingInputHandlerClient : public InputHandlerClient {
ADD_FAILURE() << "Animate called on wrong thread";
}
- void MainThreadHasStoppedFlinging() override {
- if (!task_runner_->BelongsToCurrentThread())
- ADD_FAILURE() << "MainThreadHasStoppedFlinging called on wrong thread";
- *received_stop_flinging_ = true;
- }
-
void ReconcileElasticOverscrollAndRootScroll() override {
if (!task_runner_->BelongsToCurrentThread()) {
ADD_FAILURE() << "ReconcileElasticOverscrollAndRootScroll called on "
@@ -1338,52 +1330,6 @@ class ThreadCheckingInputHandlerClient : public InputHandlerClient {
bool* received_stop_flinging_;
};
-void BindInputHandlerOnCompositorThread(
- const base::WeakPtr<InputHandler>& input_handler,
- ThreadCheckingInputHandlerClient* client) {
- input_handler->BindToClient(client, false);
-}
-
-TEST(LayerTreeHostFlingTest, DidStopFlingingThread) {
- base::Thread impl_thread("cc");
- ASSERT_TRUE(impl_thread.Start());
- ASSERT_TRUE(impl_thread.task_runner());
-
- bool received_stop_flinging = false;
- LayerTreeSettings settings;
-
- StubLayerTreeHostClient layer_tree_host_client;
- TestTaskGraphRunner task_graph_runner;
-
- auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN);
-
- LayerTreeHost::InitParams params;
- params.client = &layer_tree_host_client;
- params.task_graph_runner = &task_graph_runner;
- params.settings = &settings;
- params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
- params.mutator_host = animation_host.get();
- params.ukm_recorder_factory = std::make_unique<TestUkmRecorderFactory>();
- std::unique_ptr<LayerTreeHost> layer_tree_host =
- LayerTreeHost::CreateThreaded(impl_thread.task_runner(), &params);
-
- ThreadCheckingInputHandlerClient input_handler_client(
- impl_thread.task_runner().get(), &received_stop_flinging);
- impl_thread.task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&BindInputHandlerOnCompositorThread,
- layer_tree_host->GetInputHandler(),
- base::Unretained(&input_handler_client)));
-
- layer_tree_host->DidStopFlinging();
-
- animation_host->SetMutatorHostClient(nullptr);
- layer_tree_host = nullptr;
- animation_host = nullptr;
-
- impl_thread.Stop();
- EXPECT_TRUE(received_stop_flinging);
-}
-
class LayerTreeHostScrollTestLayerStructureChange
: public LayerTreeHostScrollTest {
public:
@@ -1554,19 +1500,19 @@ class LayerTreeHostScrollTestScrollMFBA : public LayerTreeHostScrollTest {
Layer* scroll_layer = layer_tree_host()->outer_viewport_scroll_layer();
switch (layer_tree_host()->SourceFrameNumber()) {
case 0:
- EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->CurrentScrollOffset());
break;
case 1:
EXPECT_VECTOR_EQ(
gfx::ScrollOffsetWithDelta(initial_scroll_, scroll_amount_),
- scroll_layer->scroll_offset());
+ scroll_layer->CurrentScrollOffset());
// Pretend like Javascript updated the scroll position itself.
scroll_layer->SetScrollOffset(second_scroll_);
break;
case 2:
// Third frame does not see a scroll delta because we only did one
// scroll for the second and third frames.
- EXPECT_VECTOR_EQ(second_scroll_, scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(second_scroll_, scroll_layer->CurrentScrollOffset());
// Pretend like Javascript updated the scroll position itself.
scroll_layer->SetScrollOffset(third_scroll_);
break;
@@ -1682,7 +1628,8 @@ class LayerTreeHostScrollTestScrollAbortedCommitMFBA
// This will not be aborted because of the initial prop changes.
EXPECT_EQ(0, num_impl_scrolls_);
EXPECT_EQ(0, layer_tree_host()->SourceFrameNumber());
- EXPECT_VECTOR_EQ(initial_scroll_, root_scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_,
+ root_scroll_layer->CurrentScrollOffset());
break;
case 2:
// This commit will not be aborted because of the scroll change.
@@ -1690,9 +1637,9 @@ class LayerTreeHostScrollTestScrollAbortedCommitMFBA
EXPECT_EQ(1, layer_tree_host()->SourceFrameNumber());
EXPECT_VECTOR_EQ(
gfx::ScrollOffsetWithDelta(initial_scroll_, impl_scroll_),
- root_scroll_layer->scroll_offset());
+ root_scroll_layer->CurrentScrollOffset());
root_scroll_layer->SetScrollOffset(gfx::ScrollOffsetWithDelta(
- root_scroll_layer->scroll_offset(), second_main_scroll_));
+ root_scroll_layer->CurrentScrollOffset(), second_main_scroll_));
break;
case 3: {
// This commit will be aborted.
@@ -1702,7 +1649,7 @@ class LayerTreeHostScrollTestScrollAbortedCommitMFBA
gfx::Vector2dF delta =
impl_scroll_ + impl_scroll_ + second_main_scroll_;
EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(initial_scroll_, delta),
- root_scroll_layer->scroll_offset());
+ root_scroll_layer->CurrentScrollOffset());
break;
}
case 4: {
@@ -1712,7 +1659,7 @@ class LayerTreeHostScrollTestScrollAbortedCommitMFBA
gfx::Vector2dF delta =
impl_scroll_ + impl_scroll_ + impl_scroll_ + second_main_scroll_;
EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(initial_scroll_, delta),
- root_scroll_layer->scroll_offset());
+ root_scroll_layer->CurrentScrollOffset());
break;
}
}
@@ -1869,7 +1816,6 @@ class MockInputHandlerClient : public InputHandlerClient {
void WillShutdown() override {}
void Animate(base::TimeTicks) override {}
- void MainThreadHasStoppedFlinging() override {}
void UpdateRootLayerStateForSynchronousInputHandler(
const gfx::ScrollOffset& total_scroll_offset,
const gfx::ScrollOffset& max_scroll_offset,
@@ -1905,7 +1851,7 @@ class LayerTreeHostScrollTestElasticOverscroll
void BindInputHandler(base::WeakPtr<InputHandler> input_handler) {
DCHECK(task_runner_provider()->IsImplThread());
- input_handler->BindToClient(&input_handler_client_, false);
+ input_handler->BindToClient(&input_handler_client_);
scroll_elasticity_helper_ = input_handler->CreateScrollElasticityHelper();
DCHECK(scroll_elasticity_helper_);
}
@@ -2058,11 +2004,11 @@ class LayerTreeHostScrollTestPropertyTreeUpdate
LayerTreeHostClient::VisualStateUpdate requested_update) override {
Layer* scroll_layer = layer_tree_host()->inner_viewport_scroll_layer();
if (layer_tree_host()->SourceFrameNumber() == 0) {
- EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->CurrentScrollOffset());
} else {
EXPECT_VECTOR_EQ(
gfx::ScrollOffsetWithDelta(initial_scroll_, scroll_amount_),
- scroll_layer->scroll_offset());
+ scroll_layer->CurrentScrollOffset());
scroll_layer->SetScrollOffset(second_scroll_);
scroll_layer->SetOpacity(0.5f);
}
@@ -2142,7 +2088,7 @@ class LayerTreeHostScrollTestImplSideInvalidation
gfx::ScrollOffset delta_to_send =
outer_viewport_offsets_[2] - outer_viewport_offsets_[1];
outer_viewport_layer->SetScrollOffset(
- outer_viewport_layer->scroll_offset() + delta_to_send);
+ outer_viewport_layer->CurrentScrollOffset() + delta_to_send);
} break;
case 2:
// Let the commit abort for the second set of deltas.
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index a6b06c59e26..cf474aceec6 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -90,7 +90,7 @@ LayerTreeImpl::LayerTreeImpl(
needs_update_draw_properties_(true),
scrollbar_geometries_need_update_(false),
needs_full_tree_sync_(true),
- needs_surface_ids_sync_(false),
+ needs_surface_ranges_sync_(false),
next_activation_forces_redraw_(false),
has_ever_been_drawn_(false),
handle_visibility_changed_(false),
@@ -136,6 +136,13 @@ void LayerTreeImpl::ReleaseResources() {
}
}
+void LayerTreeImpl::OnPurgeMemory() {
+ if (!LayerListIsEmpty()) {
+ LayerTreeHostCommon::CallFunctionForEveryLayer(
+ this, [](LayerImpl* layer) { layer->OnPurgeMemory(); });
+ }
+}
+
void LayerTreeImpl::ReleaseTileResources() {
if (!LayerListIsEmpty()) {
LayerTreeHostCommon::CallFunctionForEveryLayer(
@@ -228,9 +235,10 @@ void LayerTreeImpl::UpdateScrollbarGeometries() {
scrolling_size = gfx::SizeF(scroll_node->bounds);
} else {
// Add offset and bounds contribution of inner viewport.
- current_offset += InnerViewportScrollLayer()->CurrentScrollOffset();
- gfx::SizeF inner_viewport_bounds(scroll_tree.container_bounds(
- InnerViewportScrollLayer()->scroll_tree_index()));
+ current_offset += scroll_tree.current_scroll_offset(
+ InnerViewportScrollNode()->element_id);
+ gfx::SizeF inner_viewport_bounds(
+ scroll_tree.container_bounds(InnerViewportScrollNode()->id));
viewport_bounds.SetToMin(inner_viewport_bounds);
}
viewport_bounds.Scale(1 / current_page_scale_factor());
@@ -249,7 +257,7 @@ void LayerTreeImpl::UpdateScrollbarGeometries() {
}
if (is_viewport_scrollbar) {
scrollbar->SetVerticalAdjust(
- InnerViewportContainerLayer()->ViewportBoundsDelta().y());
+ property_trees_.inner_viewport_container_bounds_delta().y());
}
}
}
@@ -339,9 +347,12 @@ bool LayerTreeImpl::IsRootLayer(const LayerImpl* layer) const {
gfx::ScrollOffset LayerTreeImpl::TotalScrollOffset() const {
gfx::ScrollOffset offset;
+ auto& scroll_tree = property_trees()->scroll_tree;
- if (InnerViewportScrollLayer())
- offset += InnerViewportScrollLayer()->CurrentScrollOffset();
+ if (InnerViewportScrollNode()) {
+ offset += scroll_tree.current_scroll_offset(
+ InnerViewportScrollNode()->element_id);
+ }
if (OuterViewportScrollLayer())
offset += OuterViewportScrollLayer()->CurrentScrollOffset();
@@ -351,12 +362,13 @@ gfx::ScrollOffset LayerTreeImpl::TotalScrollOffset() const {
gfx::ScrollOffset LayerTreeImpl::TotalMaxScrollOffset() const {
gfx::ScrollOffset offset;
+ const ScrollTree& scroll_tree = property_trees()->scroll_tree;
- if (InnerViewportScrollLayer())
- offset += InnerViewportScrollLayer()->MaxScrollOffset();
+ if (auto* inner_node = InnerViewportScrollNode())
+ offset += scroll_tree.MaxScrollOffset(inner_node->id);
- if (OuterViewportScrollLayer())
- offset += OuterViewportScrollLayer()->MaxScrollOffset();
+ if (auto* outer_node = OuterViewportScrollNode())
+ offset += scroll_tree.MaxScrollOffset(outer_node->id);
return offset;
}
@@ -420,12 +432,12 @@ void LayerTreeImpl::PushPropertyTreesTo(LayerTreeImpl* target_tree) {
target_tree->SetCurrentlyScrollingNode(scrolling_node);
}
-void LayerTreeImpl::PushSurfaceIdsTo(LayerTreeImpl* target_tree) {
- if (needs_surface_ids_sync()) {
- target_tree->ClearSurfaceLayerIds();
- target_tree->SetSurfaceLayerIds(SurfaceLayerIds());
+void LayerTreeImpl::PushSurfaceRangesTo(LayerTreeImpl* target_tree) {
+ if (needs_surface_ranges_sync()) {
+ target_tree->ClearSurfaceRanges();
+ target_tree->SetSurfaceRanges(SurfaceRanges());
// Reset for next update
- set_needs_surface_ids_sync(false);
+ set_needs_surface_ranges_sync(false);
}
}
@@ -434,7 +446,7 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
// The request queue should have been processed and does not require a push.
DCHECK_EQ(ui_resource_request_queue_.size(), 0u);
- PushSurfaceIdsTo(target_tree);
+ PushSurfaceRangesTo(target_tree);
target_tree->property_trees()->scroll_tree.PushScrollUpdatesFromPendingTree(
&property_trees_, target_tree);
@@ -468,7 +480,6 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->elastic_overscroll()->PushPendingToActive();
target_tree->set_content_source_id(content_source_id());
- target_tree->set_request_presentation_time(request_presentation_time());
if (TakeNewLocalSurfaceIdRequest())
target_tree->RequestNewLocalSurfaceId();
@@ -510,6 +521,7 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
// Note: this needs to happen after SetPropertyTrees.
target_tree->HandleTickmarksVisibilityChange();
target_tree->HandleScrollbarShowRequestsFromMain();
+ target_tree->AddPresentationCallbacks(std::move(presentation_callbacks_));
}
void LayerTreeImpl::HandleTickmarksVisibilityChange() {
@@ -596,52 +608,47 @@ LayerImplList::reverse_iterator LayerTreeImpl::rend() {
return layer_list_.rend();
}
-LayerImpl* LayerTreeImpl::LayerByElementId(ElementId element_id) const {
- auto iter = element_layers_map_.find(element_id);
- return (iter == element_layers_map_.end()) ? nullptr
- : LayerById(iter->second);
+bool LayerTreeImpl::IsElementInLayerList(ElementId element_id) const {
+ return elements_in_layer_list_.count(element_id);
}
ElementListType LayerTreeImpl::GetElementTypeForAnimation() const {
return IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
}
-void LayerTreeImpl::AddToElementMap(LayerImpl* layer) {
- ElementId element_id = layer->element_id();
+void LayerTreeImpl::AddToElementLayerList(ElementId element_id) {
if (!element_id)
return;
- TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("layer-element"),
- "LayerTreeImpl::AddToElementMap", "element",
- element_id.AsValue().release(), "layer_id", layer->id());
+ TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("layer-element"),
+ "LayerTreeImpl::AddToElementLayerList", "element",
+ element_id.AsValue().release());
#if DCHECK_IS_ON()
- LayerImpl* existing_layer = LayerByElementId(element_id);
bool element_id_collision_detected =
- existing_layer && existing_layer != layer;
+ elements_in_layer_list_.count(element_id);
DCHECK(!element_id_collision_detected);
#endif
- element_layers_map_[element_id] = layer->id();
+ elements_in_layer_list_.insert(element_id);
host_impl_->mutator_host()->RegisterElement(element_id,
GetElementTypeForAnimation());
}
-void LayerTreeImpl::RemoveFromElementMap(LayerImpl* layer) {
- if (!layer->element_id())
+void LayerTreeImpl::RemoveFromElementLayerList(ElementId element_id) {
+ if (!element_id)
return;
- TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("layer-element"),
- "LayerTreeImpl::RemoveFromElementMap", "element",
- layer->element_id().AsValue().release(), "layer_id",
- layer->id());
+ TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("layer-element"),
+ "LayerTreeImpl::RemoveFromElementLayerList", "element",
+ element_id.AsValue().release());
- host_impl_->mutator_host()->UnregisterElement(layer->element_id(),
+ host_impl_->mutator_host()->UnregisterElement(element_id,
GetElementTypeForAnimation());
- element_layers_map_.erase(layer->element_id());
+ elements_in_layer_list_.erase(element_id);
}
void LayerTreeImpl::SetTransformMutated(ElementId element_id,
@@ -671,6 +678,20 @@ void LayerTreeImpl::SetFilterMutated(ElementId element_id,
set_needs_update_draw_properties();
}
+void LayerTreeImpl::AddPresentationCallbacks(
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks) {
+ std::copy(std::make_move_iterator(callbacks.begin()),
+ std::make_move_iterator(callbacks.end()),
+ std::back_inserter(presentation_callbacks_));
+}
+
+std::vector<LayerTreeHost::PresentationTimeCallback>
+LayerTreeImpl::TakePresentationCallbacks() {
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks;
+ callbacks.swap(presentation_callbacks_);
+ return callbacks;
+}
+
ScrollNode* LayerTreeImpl::CurrentlyScrollingNode() {
DCHECK(IsActiveTree());
return property_trees_.scroll_tree.CurrentlyScrollingNode();
@@ -797,19 +818,47 @@ void LayerTreeImpl::UpdateTransformAnimation(ElementId element_id,
}
}
+TransformNode* LayerTreeImpl::PageScaleTransformNode() {
+ auto* page_scale = PageScaleLayer();
+ if (!page_scale)
+ return nullptr;
+
+ return property_trees()->transform_tree.Node(
+ page_scale->transform_tree_index());
+}
+
+void LayerTreeImpl::UpdatePageScaleNode() {
+ if (!PageScaleTransformNode()) {
+ DCHECK(layer_list_.empty() || current_page_scale_factor() == 1);
+ return;
+ }
+
+ // When the page scale layer is also the root layer (this happens in the UI
+ // compositor), the node should also store the combined scale factor and not
+ // just the page scale factor.
+ // TODO(bokan): Need to implement this behavior for
+ // BlinkGeneratedPropertyTrees. i.e. (no page scale layer).
+ float device_scale_factor_for_page_scale_layer = 1.f;
+ gfx::Transform device_transform_for_page_scale_layer;
+ if (IsRootLayer(PageScaleLayer())) {
+ DCHECK(!settings().use_layer_lists);
+ device_transform_for_page_scale_layer = host_impl_->DrawTransform();
+ device_scale_factor_for_page_scale_layer = device_scale_factor();
+ }
+
+ draw_property_utils::UpdatePageScaleFactor(
+ property_trees(), PageScaleTransformNode(), current_page_scale_factor(),
+ device_scale_factor_for_page_scale_layer,
+ device_transform_for_page_scale_layer);
+}
+
void LayerTreeImpl::SetPageScaleOnActiveTree(float active_page_scale) {
DCHECK(IsActiveTree());
DCHECK(lifecycle().AllowsPropertyTreeAccess());
if (page_scale_factor()->SetCurrent(
ClampPageScaleFactorToLimits(active_page_scale))) {
DidUpdatePageScale();
- if (PageScaleLayer()) {
- draw_property_utils::UpdatePageScaleFactor(
- property_trees(), PageScaleLayer(), current_page_scale_factor(),
- device_scale_factor(), host_impl_->DrawTransform());
- } else {
- DCHECK(layer_list_.empty() || active_page_scale == 1);
- }
+ UpdatePageScaleNode();
}
}
@@ -843,15 +892,8 @@ void LayerTreeImpl::PushPageScaleFactorAndLimits(const float* page_scale_factor,
DidUpdatePageScale();
DCHECK(lifecycle().AllowsPropertyTreeAccess());
- if (page_scale_factor) {
- if (PageScaleLayer()) {
- draw_property_utils::UpdatePageScaleFactor(
- property_trees(), PageScaleLayer(), current_page_scale_factor(),
- device_scale_factor(), host_impl_->DrawTransform());
- } else {
- DCHECK(layer_list_.empty() || *page_scale_factor == 1);
- }
- }
+ if (page_scale_factor)
+ UpdatePageScaleNode();
}
void LayerTreeImpl::set_browser_controls_shrink_blink_size(bool shrink) {
@@ -999,10 +1041,11 @@ const SyncedProperty<ScaleGroup>* LayerTreeImpl::page_scale_factor() const {
}
gfx::SizeF LayerTreeImpl::ScrollableViewportSize() const {
- if (!InnerViewportContainerLayer())
+ auto* inner_node = InnerViewportScrollNode();
+ if (!inner_node)
return gfx::SizeF();
- return gfx::ScaleSize(InnerViewportContainerLayer()->BoundsForScrolling(),
+ return gfx::ScaleSize(gfx::SizeF(inner_node->container_bounds),
1.0f / current_page_scale_factor());
}
@@ -1051,6 +1094,21 @@ void LayerTreeImpl::ClearViewportLayers() {
SetViewportLayersFromIds(ViewportLayerIds());
}
+const ScrollNode* LayerTreeImpl::InnerViewportScrollNode() const {
+ auto* inner_scroll = InnerViewportScrollLayer();
+ if (!inner_scroll)
+ return nullptr;
+
+ return property_trees()->scroll_tree.Node(inner_scroll->scroll_tree_index());
+}
+
+const ScrollNode* LayerTreeImpl::OuterViewportScrollNode() const {
+ if (!OuterViewportScrollLayer())
+ return nullptr;
+ return property_trees()->scroll_tree.Node(
+ OuterViewportScrollLayer()->scroll_tree_index());
+}
+
// For unit tests, we use the layer's id as its element id.
static void SetElementIdForTesting(LayerImpl* layer) {
layer->SetElementId(LayerIdToElementIdForTesting(layer->id()));
@@ -1105,7 +1163,7 @@ bool LayerTreeImpl::UpdateDrawProperties(
elastic_overscroll()->Current(IsActiveTree()),
OverscrollElasticityLayer(), max_texture_size(),
settings().layer_transforms_should_scale_layer_contents,
- &render_surface_list_, &property_trees_);
+ &render_surface_list_, &property_trees_, PageScaleTransformNode());
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
if (const char* client_name = GetClientNameForMetrics()) {
UMA_HISTOGRAM_COUNTS(
@@ -1277,20 +1335,20 @@ LayerImpl* LayerTreeImpl::LayerById(int id) const {
return iter != layer_id_map_.end() ? iter->second : nullptr;
}
-void LayerTreeImpl::SetSurfaceLayerIds(
- const base::flat_set<viz::SurfaceId>& surface_layer_ids) {
- DCHECK(surface_layer_ids_.empty());
- surface_layer_ids_ = surface_layer_ids;
- needs_surface_ids_sync_ = true;
+void LayerTreeImpl::SetSurfaceRanges(
+ const base::flat_set<viz::SurfaceRange> surface_ranges) {
+ DCHECK(surface_layer_ranges_.empty());
+ surface_layer_ranges_ = std::move(surface_ranges);
+ needs_surface_ranges_sync_ = true;
}
-const base::flat_set<viz::SurfaceId>& LayerTreeImpl::SurfaceLayerIds() const {
- return surface_layer_ids_;
+const base::flat_set<viz::SurfaceRange>& LayerTreeImpl::SurfaceRanges() const {
+ return surface_layer_ranges_;
}
-void LayerTreeImpl::ClearSurfaceLayerIds() {
- surface_layer_ids_.clear();
- needs_surface_ids_sync_ = true;
+void LayerTreeImpl::ClearSurfaceRanges() {
+ surface_layer_ranges_.clear();
+ needs_surface_ranges_sync_ = true;
}
void LayerTreeImpl::AddLayerShouldPushProperties(LayerImpl* layer) {
@@ -1410,7 +1468,7 @@ viz::ContextProvider* LayerTreeImpl::context_provider() const {
return host_impl_->layer_tree_frame_sink()->context_provider();
}
-LayerTreeResourceProvider* LayerTreeImpl::resource_provider() const {
+viz::ClientResourceProvider* LayerTreeImpl::resource_provider() const {
return host_impl_->resource_provider();
}
@@ -1588,19 +1646,30 @@ void LayerTreeImpl::AsValueInto(base::trace_event::TracedValue* state) const {
}
bool LayerTreeImpl::DistributeRootScrollOffset(
- const gfx::ScrollOffset& root_offset) {
- if (!InnerViewportScrollLayer() || !OuterViewportScrollLayer())
+ const gfx::ScrollOffset& desired_root_offset) {
+ if (!InnerViewportScrollNode() || !OuterViewportScrollLayer())
return false;
+ gfx::ScrollOffset root_offset = desired_root_offset;
+ ScrollTree& scroll_tree = property_trees()->scroll_tree;
+
// If we get here, we have both inner/outer viewports, and need to distribute
// the scroll offset between them.
gfx::ScrollOffset inner_viewport_offset =
- InnerViewportScrollLayer()->CurrentScrollOffset();
+ scroll_tree.current_scroll_offset(InnerViewportScrollNode()->element_id);
gfx::ScrollOffset outer_viewport_offset =
OuterViewportScrollLayer()->CurrentScrollOffset();
+ DCHECK(inner_viewport_offset + outer_viewport_offset == TotalScrollOffset());
+
+ // Setting the root scroll offset is driven by user actions so prevent
+ // it if it is not user scrollable in certain directions.
+ if (!InnerViewportScrollNode()->user_scrollable_horizontal)
+ root_offset.set_x(inner_viewport_offset.x() + outer_viewport_offset.x());
+
+ if (!InnerViewportScrollNode()->user_scrollable_vertical)
+ root_offset.set_y(inner_viewport_offset.y() + outer_viewport_offset.y());
// It may be nothing has changed.
- DCHECK(inner_viewport_offset + outer_viewport_offset == TotalScrollOffset());
if (inner_viewport_offset + outer_viewport_offset == root_offset)
return false;
@@ -1613,7 +1682,9 @@ bool LayerTreeImpl::DistributeRootScrollOffset(
OuterViewportScrollLayer()->SetCurrentScrollOffset(outer_viewport_offset);
inner_viewport_offset = root_offset - outer_viewport_offset;
- InnerViewportScrollLayer()->SetCurrentScrollOffset(inner_viewport_offset);
+ if (scroll_tree.SetScrollOffset(InnerViewportScrollNode()->element_id,
+ inner_viewport_offset))
+ DidUpdateScrollOffset(InnerViewportScrollNode()->element_id);
return true;
}
@@ -1632,15 +1703,8 @@ void LayerTreeImpl::QueuePinnedSwapPromise(
void LayerTreeImpl::PassSwapPromises(
std::vector<std::unique_ptr<SwapPromise>> new_swap_promises) {
- for (auto& swap_promise : swap_promise_list_) {
- if (swap_promise->DidNotSwap(SwapPromise::SWAP_FAILS) ==
- SwapPromise::DidNotSwapAction::KEEP_ACTIVE) {
- // |swap_promise| must remain active, so place it in |new_swap_promises|
- // in order to keep it alive and active.
- new_swap_promises.push_back(std::move(swap_promise));
- }
- }
- swap_promise_list_.clear();
+ for (auto& swap_promise : swap_promise_list_)
+ swap_promise->DidNotSwap(SwapPromise::SWAP_FAILS);
swap_promise_list_.swap(new_swap_promises);
}
@@ -1651,13 +1715,11 @@ void LayerTreeImpl::AppendSwapPromises(
new_swap_promises.clear();
}
-void LayerTreeImpl::FinishSwapPromises(
- viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator) {
+void LayerTreeImpl::FinishSwapPromises(viz::CompositorFrameMetadata* metadata) {
for (const auto& swap_promise : swap_promise_list_)
- swap_promise->WillSwap(metadata, frame_token_allocator);
+ swap_promise->WillSwap(metadata);
for (const auto& swap_promise : pinned_swap_promise_list_)
- swap_promise->WillSwap(metadata, frame_token_allocator);
+ swap_promise->WillSwap(metadata);
}
void LayerTreeImpl::ClearSwapPromises() {
@@ -1670,30 +1732,13 @@ void LayerTreeImpl::ClearSwapPromises() {
}
void LayerTreeImpl::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) {
- {
- std::vector<std::unique_ptr<SwapPromise>> persistent_swap_promises;
- for (auto& swap_promise : swap_promise_list_) {
- if (swap_promise->DidNotSwap(reason) ==
- SwapPromise::DidNotSwapAction::KEEP_ACTIVE) {
- persistent_swap_promises.push_back(std::move(swap_promise));
- }
- }
- // |persistent_swap_promises| must remain active even when swap fails.
- swap_promise_list_ = std::move(persistent_swap_promises);
- }
-
- {
- std::vector<std::unique_ptr<SwapPromise>> persistent_swap_promises;
- for (auto& swap_promise : pinned_swap_promise_list_) {
- if (swap_promise->DidNotSwap(reason) ==
- SwapPromise::DidNotSwapAction::KEEP_ACTIVE) {
- persistent_swap_promises.push_back(std::move(swap_promise));
- }
- }
+ for (auto& swap_promise : swap_promise_list_)
+ swap_promise->DidNotSwap(reason);
+ swap_promise_list_.clear();
- // |persistent_swap_promises| must remain active even when swap fails.
- pinned_swap_promise_list_ = std::move(persistent_swap_promises);
- }
+ for (auto& swap_promise : pinned_swap_promise_list_)
+ swap_promise->DidNotSwap(reason);
+ pinned_swap_promise_list_.clear();
}
void LayerTreeImpl::DidModifyTilePriorities() {
@@ -1863,31 +1908,6 @@ static bool PointHitsRect(
return true;
}
-static bool PointHitsRegion(const gfx::PointF& screen_space_point,
- const gfx::Transform& screen_space_transform,
- const Region& layer_space_region) {
- // If the transform is not invertible, then assume that this point doesn't hit
- // this region.
- gfx::Transform inverse_screen_space_transform(
- gfx::Transform::kSkipInitialization);
- if (!screen_space_transform.GetInverse(&inverse_screen_space_transform))
- return false;
-
- // Transform the hit test point from screen space to the local space of the
- // given region.
- bool clipped = false;
- gfx::PointF hit_test_point_in_layer_space = MathUtil::ProjectPoint(
- inverse_screen_space_transform, screen_space_point, &clipped);
-
- // If ProjectPoint could not project to a valid value, then we assume that
- // this point doesn't hit this region.
- if (clipped)
- return false;
-
- return layer_space_region.Contains(
- gfx::ToRoundedPoint(hit_test_point_in_layer_space));
-}
-
static bool PointIsClippedByAncestorClipNode(
const gfx::PointF& screen_space_point,
const LayerImpl* layer) {
@@ -1933,6 +1953,41 @@ static bool PointIsClippedBySurfaceOrClipRect(
return PointIsClippedByAncestorClipNode(screen_space_point, layer);
}
+static bool PointHitsRegion(const gfx::PointF& screen_space_point,
+ const gfx::Transform& screen_space_transform,
+ const Region& layer_space_region,
+ const LayerImpl* layer_impl) {
+ if (layer_space_region.IsEmpty())
+ return false;
+
+ // If the transform is not invertible, then assume that this point doesn't hit
+ // this region.
+ gfx::Transform inverse_screen_space_transform(
+ gfx::Transform::kSkipInitialization);
+ if (!screen_space_transform.GetInverse(&inverse_screen_space_transform))
+ return false;
+
+ // Transform the hit test point from screen space to the local space of the
+ // given region.
+ bool clipped = false;
+ gfx::PointF hit_test_point_in_layer_space = MathUtil::ProjectPoint(
+ inverse_screen_space_transform, screen_space_point, &clipped);
+
+ // If ProjectPoint could not project to a valid value, then we assume that
+ // this point doesn't hit this region.
+ if (clipped)
+ return false;
+
+ // We need to walk up the parents to ensure that the layer is not clipped in
+ // such a way that it is impossible for the point to hit the layer.
+ if (layer_impl &&
+ PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl))
+ return false;
+
+ return layer_space_region.Contains(
+ gfx::ToRoundedPoint(hit_test_point_in_layer_space));
+}
+
static bool PointHitsLayer(const LayerImpl* layer,
const gfx::PointF& screen_space_point,
float* distance_to_intersection) {
@@ -2043,44 +2098,49 @@ LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPoint(
return state.closest_match;
}
-static bool LayerHasTouchEventHandlersAt(const gfx::PointF& screen_space_point,
- LayerImpl* layer_impl) {
- if (layer_impl->touch_action_region().region().IsEmpty())
- return false;
-
- if (!PointHitsRegion(screen_space_point, layer_impl->ScreenSpaceTransform(),
- layer_impl->touch_action_region().region()))
- return false;
-
- // At this point, we think the point does hit the touch event handler region
- // on the layer, but we need to walk up the parents to ensure that the layer
- // was not clipped in such a way that the hit point actually should not hit
- // the layer.
- if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl))
- return false;
-
- return true;
-}
-
struct FindTouchEventLayerFunctor {
bool operator()(LayerImpl* layer) const {
- return LayerHasTouchEventHandlersAt(screen_space_point, layer);
+ return PointHitsRegion(screen_space_point, layer->ScreenSpaceTransform(),
+ layer->touch_action_region().region(), layer);
}
const gfx::PointF screen_space_point;
};
-LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion(
- const gfx::PointF& screen_space_point) {
+struct FindWheelEventHandlerLayerFunctor {
+ bool operator()(LayerImpl* layer) const {
+ return PointHitsRegion(screen_space_point, layer->ScreenSpaceTransform(),
+ layer->wheel_event_handler_region(), layer);
+ }
+ const gfx::PointF screen_space_point;
+};
+
+template <typename Functor>
+LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInEventHandlerRegion(
+ const gfx::PointF& screen_space_point,
+ const Functor& func) {
if (layer_list_.empty())
return nullptr;
if (!UpdateDrawProperties())
return nullptr;
- FindTouchEventLayerFunctor func = {screen_space_point};
FindClosestMatchingLayerState state;
FindClosestMatchingLayer(screen_space_point, layer_list_[0], func, &state);
return state.closest_match;
}
+LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion(
+ const gfx::PointF& screen_space_point) {
+ FindTouchEventLayerFunctor func = {screen_space_point};
+ return FindLayerThatIsHitByPointInEventHandlerRegion(screen_space_point,
+ func);
+}
+
+LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInWheelEventHandlerRegion(
+ const gfx::PointF& screen_space_point) {
+ FindWheelEventHandlerLayerFunctor func = {screen_space_point};
+ return FindLayerThatIsHitByPointInEventHandlerRegion(screen_space_point,
+ func);
+}
+
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 11e406e78d4..0bbf294437e 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -20,6 +20,7 @@
#include "cc/layers/layer_impl.h"
#include "cc/layers/layer_list_iterator.h"
#include "cc/resources/ui_resource_client.h"
+#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/property_tree.h"
#include "cc/trees/swap_promise.h"
@@ -32,6 +33,7 @@ class TracedValue;
}
namespace viz {
+class ClientResourceProvider;
class ContextProvider;
}
@@ -44,7 +46,6 @@ class ImageDecodeCache;
class LayerTreeDebugState;
class LayerTreeImpl;
class LayerTreeFrameSink;
-class LayerTreeResourceProvider;
class LayerTreeSettings;
class MemoryHistory;
class PictureLayerImpl;
@@ -100,6 +101,7 @@ class CC_EXPORT LayerTreeImpl {
void Shutdown();
void ReleaseResources();
+ void OnPurgeMemory();
void ReleaseTileResources();
void RecreateTileResources();
@@ -110,7 +112,7 @@ class CC_EXPORT LayerTreeImpl {
const LayerTreeSettings& settings() const;
const LayerTreeDebugState& debug_state() const;
viz::ContextProvider* context_provider() const;
- LayerTreeResourceProvider* resource_provider() const;
+ viz::ClientResourceProvider* resource_provider() const;
TileManager* tile_manager() const;
ImageDecodeCache* image_decode_cache() const;
ImageAnimationController* image_animation_controller() const;
@@ -179,7 +181,7 @@ class CC_EXPORT LayerTreeImpl {
void PushPropertyTreesTo(LayerTreeImpl* tree_impl);
void PushPropertiesTo(LayerTreeImpl* tree_impl);
- void PushSurfaceIdsTo(LayerTreeImpl* tree_impl);
+ void PushSurfaceRangesTo(LayerTreeImpl* tree_impl);
void MoveChangeTrackingToLayers();
@@ -220,6 +222,14 @@ class CC_EXPORT LayerTreeImpl {
gfx::ScrollOffset TotalScrollOffset() const;
gfx::ScrollOffset TotalMaxScrollOffset() const;
+ void AddPresentationCallbacks(
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks);
+ std::vector<LayerTreeHost::PresentationTimeCallback>
+ TakePresentationCallbacks();
+ bool has_presentation_callbacks() const {
+ return !presentation_callbacks_.empty();
+ }
+
ScrollNode* CurrentlyScrollingNode();
const ScrollNode* CurrentlyScrollingNode() const;
int LastScrolledScrollNodeIndex() const;
@@ -264,6 +274,17 @@ class CC_EXPORT LayerTreeImpl {
return LayerById(viewport_layer_ids_.outer_viewport_scroll);
}
+ const ScrollNode* InnerViewportScrollNode() const;
+ ScrollNode* InnerViewportScrollNode() {
+ return const_cast<ScrollNode*>(
+ const_cast<const LayerTreeImpl*>(this)->InnerViewportScrollNode());
+ }
+ const ScrollNode* OuterViewportScrollNode() const;
+ ScrollNode* OuterViewportScrollNode() {
+ return const_cast<ScrollNode*>(
+ const_cast<const LayerTreeImpl*>(this)->OuterViewportScrollNode());
+ }
+
void ApplySentScrollAndScaleDeltasFromAbortedCommit();
SkColor background_color() const { return background_color_; }
@@ -355,9 +376,9 @@ class CC_EXPORT LayerTreeImpl {
void set_needs_full_tree_sync(bool needs) { needs_full_tree_sync_ = needs; }
bool needs_full_tree_sync() const { return needs_full_tree_sync_; }
- bool needs_surface_ids_sync() const { return needs_surface_ids_sync_; }
- void set_needs_surface_ids_sync(bool needs_surface_ids_sync) {
- needs_surface_ids_sync_ = needs_surface_ids_sync;
+ bool needs_surface_ranges_sync() const { return needs_surface_ranges_sync_; }
+ void set_needs_surface_ranges_sync(bool needs_surface_ranges_sync) {
+ needs_surface_ranges_sync_ = needs_surface_ranges_sync;
}
void ForceRedrawNextActivation() { next_activation_forces_redraw_ = true; }
@@ -381,16 +402,13 @@ class CC_EXPORT LayerTreeImpl {
LayerImpl* LayerById(int id) const;
- // TODO(jaydasika): this is deprecated. It is used by
- // scrolling animation to look up layers to mutate.
- LayerImpl* LayerByElementId(ElementId element_id) const;
- void AddToElementMap(LayerImpl* layer);
- void RemoveFromElementMap(LayerImpl* layer);
+ bool IsElementInLayerList(ElementId element_id) const;
+ void AddToElementLayerList(ElementId element_id);
+ void RemoveFromElementLayerList(ElementId element_id);
- void SetSurfaceLayerIds(
- const base::flat_set<viz::SurfaceId>& surface_layer_ids);
- const base::flat_set<viz::SurfaceId>& SurfaceLayerIds() const;
- void ClearSurfaceLayerIds();
+ void SetSurfaceRanges(const base::flat_set<viz::SurfaceRange> surface_ranges);
+ const base::flat_set<viz::SurfaceRange>& SurfaceRanges() const;
+ void ClearSurfaceRanges();
void AddLayerShouldPushProperties(LayerImpl* layer);
void RemoveLayerShouldPushProperties(LayerImpl* layer);
@@ -454,8 +472,7 @@ class CC_EXPORT LayerTreeImpl {
std::vector<std::unique_ptr<SwapPromise>> new_swap_promises);
void AppendSwapPromises(
std::vector<std::unique_ptr<SwapPromise>> new_swap_promises);
- void FinishSwapPromises(viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator);
+ void FinishSwapPromises(viz::CompositorFrameMetadata* metadata);
void ClearSwapPromises();
void BreakSwapPromises(SwapPromise::DidNotSwapReason reason);
@@ -484,6 +501,9 @@ class CC_EXPORT LayerTreeImpl {
LayerImpl* FindLayerThatIsHitByPointInTouchHandlerRegion(
const gfx::PointF& screen_space_point);
+ LayerImpl* FindLayerThatIsHitByPointInWheelEventHandlerRegion(
+ const gfx::PointF& screen_space_point);
+
void RegisterSelection(const LayerSelection& selection);
bool HandleVisibilityChanged() const { return handle_visibility_changed_; }
@@ -568,11 +588,6 @@ class CC_EXPORT LayerTreeImpl {
LayerTreeLifecycle& lifecycle() { return lifecycle_; }
- bool request_presentation_time() const { return request_presentation_time_; }
- void set_request_presentation_time(bool value) {
- request_presentation_time_ = value;
- }
-
protected:
float ClampPageScaleFactorToLimits(float page_scale_factor) const;
void PushPageScaleFactorAndLimits(const float* page_scale_factor,
@@ -585,8 +600,15 @@ class CC_EXPORT LayerTreeImpl {
bool ClampBrowserControlsShownRatio();
private:
+ TransformNode* PageScaleTransformNode();
+ void UpdatePageScaleNode();
+
ElementListType GetElementTypeForAnimation() const;
void UpdateTransformAnimation(ElementId element_id, int transform_node_index);
+ template <typename Functor>
+ LayerImpl* FindLayerThatIsHitByPointInEventHandlerRegion(
+ const gfx::PointF& screen_space_point,
+ const Functor& func);
LayerTreeHostImpl* host_impl_;
int source_frame_number_;
@@ -623,7 +645,8 @@ class CC_EXPORT LayerTreeImpl {
// Set of layers that need to push properties.
std::unordered_set<LayerImpl*> layers_that_should_push_properties_;
- std::unordered_map<ElementId, int, ElementIdHash> element_layers_map_;
+ // Set of ElementIds which are present in the |layer_list_|.
+ std::unordered_set<ElementId, ElementIdHash> elements_in_layer_list_;
std::unordered_map<ElementId, float, ElementIdHash>
element_id_to_opacity_animations_;
@@ -643,7 +666,7 @@ class CC_EXPORT LayerTreeImpl {
std::vector<PictureLayerImpl*> picture_layers_;
- base::flat_set<viz::SurfaceId> surface_layer_ids_;
+ base::flat_set<viz::SurfaceRange> surface_layer_ranges_;
// List of render surfaces for the most recently prepared frame.
RenderSurfaceList render_surface_list_;
@@ -662,7 +685,7 @@ class CC_EXPORT LayerTreeImpl {
// structural differences relative to the active tree.
bool needs_full_tree_sync_;
- bool needs_surface_ids_sync_;
+ bool needs_surface_ranges_sync_;
bool next_activation_forces_redraw_;
@@ -676,8 +699,8 @@ class CC_EXPORT LayerTreeImpl {
UIResourceRequestQueue ui_resource_request_queue_;
bool have_scroll_event_handlers_;
- EventListenerProperties event_listener_properties_[static_cast<size_t>(
- EventListenerClass::kNumClasses)];
+ EventListenerProperties event_listener_properties_
+ [static_cast<size_t>(EventListenerClass::kLast) + 1];
// Whether or not Blink's viewport size was shrunk by the height of the top
// controls at the time of the last layout.
@@ -697,9 +720,7 @@ class CC_EXPORT LayerTreeImpl {
// lifecycle states. See: |LayerTreeLifecycle|.
LayerTreeLifecycle lifecycle_;
- // If true LayerTreeHostImpl requests a presentation token for the current
- // frame.
- bool request_presentation_time_ = false;
+ std::vector<LayerTreeHost::PresentationTimeCallback> presentation_callbacks_;
DISALLOW_COPY_AND_ASSIGN(LayerTreeImpl);
};
diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc
index 3856dcd0c42..f4c3368e96a 100644
--- a/chromium/cc/trees/layer_tree_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_impl_unittest.cc
@@ -2277,42 +2277,16 @@ TEST_F(LayerTreeImplTest, HitTestingCorrectLayerWheelListener) {
namespace {
-class PersistentSwapPromise
- : public SwapPromise,
- public base::SupportsWeakPtr<PersistentSwapPromise> {
+class StubSwapPromise : public SwapPromise,
+ public base::SupportsWeakPtr<StubSwapPromise> {
public:
- PersistentSwapPromise() = default;
- ~PersistentSwapPromise() override = default;
+ StubSwapPromise() = default;
+ ~StubSwapPromise() override = default;
void DidActivate() override {}
- MOCK_METHOD2(WillSwap,
- void(viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator));
- MOCK_METHOD0(DidSwap, void());
-
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
- return DidNotSwapAction::KEEP_ACTIVE;
- }
-
- void OnCommit() override {}
- int64_t TraceId() const override { return 0; }
-};
-
-class NotPersistentSwapPromise
- : public SwapPromise,
- public base::SupportsWeakPtr<NotPersistentSwapPromise> {
- public:
- NotPersistentSwapPromise() = default;
- ~NotPersistentSwapPromise() override = default;
-
- void DidActivate() override {}
- void WillSwap(viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator) override {}
+ void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
void DidSwap() override {}
-
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
- return DidNotSwapAction::BREAK_PROMISE;
- }
+ void DidNotSwap(DidNotSwapReason reason) override {}
void OnCommit() override {}
int64_t TraceId() const override { return 0; }
@@ -2320,64 +2294,31 @@ class NotPersistentSwapPromise
} // namespace
-TEST_F(LayerTreeImplTest, PersistentSwapPromisesAreKeptAlive) {
- const size_t promises_count = 2;
-
- std::vector<base::WeakPtr<PersistentSwapPromise>> persistent_promises;
- std::vector<std::unique_ptr<PersistentSwapPromise>>
- persistent_promises_to_pass;
- for (size_t i = 0; i < promises_count; ++i) {
- persistent_promises_to_pass.push_back(
- std::make_unique<PersistentSwapPromise>());
- }
-
- for (auto& promise : persistent_promises_to_pass) {
- persistent_promises.push_back(promise->AsWeakPtr());
- host_impl().active_tree()->QueueSwapPromise(std::move(promise));
- }
-
- std::vector<std::unique_ptr<SwapPromise>> promises;
- host_impl().active_tree()->PassSwapPromises(std::move(promises));
- host_impl().active_tree()->BreakSwapPromises(
- SwapPromise::DidNotSwapReason::SWAP_FAILS);
-
- ASSERT_EQ(promises_count, persistent_promises.size());
- for (size_t i = 0; i < persistent_promises.size(); ++i) {
- SCOPED_TRACE(testing::Message() << "While checking case #" << i);
- ASSERT_TRUE(persistent_promises[i]);
- EXPECT_CALL(*persistent_promises[i], WillSwap(testing::_, testing::_));
- }
- host_impl().active_tree()->FinishSwapPromises(nullptr, nullptr);
-}
-
-TEST_F(LayerTreeImplTest, NotPersistentSwapPromisesAreDroppedWhenSwapFails) {
+TEST_F(LayerTreeImplTest, StubSwapPromisesAreDroppedWhenSwapFails) {
const size_t promises_count = 2;
- std::vector<base::WeakPtr<NotPersistentSwapPromise>> not_persistent_promises;
- std::vector<std::unique_ptr<NotPersistentSwapPromise>>
- not_persistent_promises_to_pass;
+ std::vector<base::WeakPtr<StubSwapPromise>> weak_swap_promises;
+ std::vector<std::unique_ptr<StubSwapPromise>> swap_promises_to_pass;
for (size_t i = 0; i < promises_count; ++i) {
- not_persistent_promises_to_pass.push_back(
- std::make_unique<NotPersistentSwapPromise>());
+ swap_promises_to_pass.push_back(std::make_unique<StubSwapPromise>());
}
- for (auto& promise : not_persistent_promises_to_pass) {
- not_persistent_promises.push_back(promise->AsWeakPtr());
+ for (auto& promise : swap_promises_to_pass) {
+ weak_swap_promises.push_back(promise->AsWeakPtr());
host_impl().active_tree()->QueueSwapPromise(std::move(promise));
}
std::vector<std::unique_ptr<SwapPromise>> promises;
host_impl().active_tree()->PassSwapPromises(std::move(promises));
- ASSERT_EQ(promises_count, not_persistent_promises.size());
- for (size_t i = 0; i < not_persistent_promises.size(); ++i) {
- EXPECT_FALSE(not_persistent_promises[i]) << "While checking case #" << i;
+ ASSERT_EQ(promises_count, weak_swap_promises.size());
+ for (size_t i = 0; i < weak_swap_promises.size(); ++i) {
+ EXPECT_FALSE(weak_swap_promises[i]) << "While checking case #" << i;
}
- // Finally, check that not persistent promise doesn't survive
+ // Finally, check that the promises do not survive
// |LayerTreeImpl::BreakSwapPromises|.
{
- std::unique_ptr<NotPersistentSwapPromise> promise(
- new NotPersistentSwapPromise());
+ std::unique_ptr<StubSwapPromise> promise(new StubSwapPromise());
auto weak_promise = promise->AsWeakPtr();
host_impl().active_tree()->QueueSwapPromise(std::move(promise));
host_impl().active_tree()->BreakSwapPromises(
diff --git a/chromium/cc/trees/layer_tree_mutator.cc b/chromium/cc/trees/layer_tree_mutator.cc
index bccd86c124e..addb4719ffe 100644
--- a/chromium/cc/trees/layer_tree_mutator.cc
+++ b/chromium/cc/trees/layer_tree_mutator.cc
@@ -4,12 +4,88 @@
#include "cc/trees/layer_tree_mutator.h"
+#include <algorithm>
+
namespace cc {
+AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState(
+ WorkletAnimationId worklet_animation_id,
+ std::string name,
+ double current_time,
+ std::unique_ptr<AnimationOptions> options)
+ : worklet_animation_id(worklet_animation_id),
+ name(name),
+ current_time(current_time),
+ options(std::move(options)) {}
+AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState(
+ AddAndUpdateState&&) = default;
+AnimationWorkletInput::AddAndUpdateState::~AddAndUpdateState() = default;
+
+#if DCHECK_IS_ON()
+bool AnimationWorkletInput::ValidateScope(int scope_id) const {
+ return std::all_of(added_and_updated_animations.cbegin(),
+ added_and_updated_animations.cend(),
+ [scope_id](auto& it) {
+ return it.worklet_animation_id.scope_id == scope_id;
+ }) &&
+ std::all_of(updated_animations.cbegin(), updated_animations.cend(),
+ [scope_id](auto& it) {
+ return it.worklet_animation_id.scope_id == scope_id;
+ }) &&
+ std::all_of(removed_animations.cbegin(), removed_animations.cend(),
+ [scope_id](auto& it) { return it.scope_id == scope_id; });
+}
+#endif
+
+AnimationWorkletInput::AnimationWorkletInput() = default;
+AnimationWorkletInput::~AnimationWorkletInput() = default;
+
MutatorInputState::MutatorInputState() = default;
MutatorInputState::~MutatorInputState() = default;
-MutatorOutputState::MutatorOutputState() = default;
-MutatorOutputState::~MutatorOutputState() = default;
+bool MutatorInputState::IsEmpty() const {
+ // If there is an AnimationWorkletInput entry in the map then that entry is
+ // guranteed to be non-empty. So checking |inputs_| map emptiness is
+ // sufficient.
+ return inputs_.empty();
+}
+
+AnimationWorkletInput& MutatorInputState::EnsureWorkletEntry(int id) {
+ auto it = inputs_.find(id);
+ if (it == inputs_.end())
+ it = inputs_.emplace_hint(it, id, new AnimationWorkletInput);
+
+ return *it->second;
+}
+
+void MutatorInputState::Add(AnimationWorkletInput::AddAndUpdateState&& state) {
+ AnimationWorkletInput& worklet_input =
+ EnsureWorkletEntry(state.worklet_animation_id.scope_id);
+ worklet_input.added_and_updated_animations.push_back(std::move(state));
+}
+void MutatorInputState::Update(AnimationWorkletInput::UpdateState&& state) {
+ AnimationWorkletInput& worklet_input =
+ EnsureWorkletEntry(state.worklet_animation_id.scope_id);
+ worklet_input.updated_animations.push_back(std::move(state));
+}
+void MutatorInputState::Remove(WorkletAnimationId worklet_animation_id) {
+ AnimationWorkletInput& worklet_input =
+ EnsureWorkletEntry(worklet_animation_id.scope_id);
+ worklet_input.removed_animations.push_back(worklet_animation_id);
+}
+
+std::unique_ptr<AnimationWorkletInput> MutatorInputState::TakeWorkletState(
+ int scope_id) {
+ auto it = inputs_.find(scope_id);
+ if (it == inputs_.end())
+ return nullptr;
+
+ std::unique_ptr<AnimationWorkletInput> result = std::move(it->second);
+ inputs_.erase(it);
+ return result;
+}
+
+AnimationWorkletOutput::AnimationWorkletOutput() = default;
+AnimationWorkletOutput::~AnimationWorkletOutput() = default;
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_mutator.h b/chromium/cc/trees/layer_tree_mutator.h
index 70cf3fc77bc..700549fa1d7 100644
--- a/chromium/cc/trees/layer_tree_mutator.h
+++ b/chromium/cc/trees/layer_tree_mutator.h
@@ -8,36 +8,100 @@
#include "base/callback_forward.h"
#include "base/time/time.h"
#include "cc/cc_export.h"
+#include "cc/trees/animation_options.h"
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
namespace cc {
-// TODO(majidvp): Currently the sync mechanism between cc and worklet is
-// stateless meaning that it sends a new copy of the world every sync cycle.
-// This has the benefit of keeping things very simple but we should revisit this
-// and only send data relevant to particular phase of animator lifecycle e.g.,
-// name and options dictionary are used just for construction.
-struct CC_EXPORT MutatorInputState {
- struct CC_EXPORT AnimationState {
- int animation_id = 0;
+struct CC_EXPORT WorkletAnimationId {
+ // Uniquely identifies the animation worklet with which this animation is
+ // associated.
+ int scope_id;
+ // Uniquely identifies the animation within its animation worklet. Note that
+ // animation_id is only guaranteed to be unique per animation worklet.
+ int animation_id;
+
+ inline bool operator==(const WorkletAnimationId& rhs) const {
+ return (this->scope_id == rhs.scope_id) &&
+ (this->animation_id == rhs.animation_id);
+ }
+};
+
+struct CC_EXPORT AnimationWorkletInput {
+ struct CC_EXPORT AddAndUpdateState {
+ WorkletAnimationId worklet_animation_id;
// Name associated with worklet animation.
std::string name;
// Worklet animation's current time, from its associated timeline.
+ double current_time;
+ std::unique_ptr<AnimationOptions> options;
+
+ AddAndUpdateState(WorkletAnimationId worklet_animation_id,
+ std::string name,
+ double current_time,
+ std::unique_ptr<AnimationOptions> options);
+
+ AddAndUpdateState(AddAndUpdateState&&);
+ ~AddAndUpdateState();
+ };
+ struct CC_EXPORT UpdateState {
+ WorkletAnimationId worklet_animation_id;
+ // Worklet animation's current time, from its associated timeline.
double current_time = 0;
};
+ // Note: When adding any new fields please also update ValidateScope to
+ // reflect them if necessary.
+ std::vector<AddAndUpdateState> added_and_updated_animations;
+ std::vector<UpdateState> updated_animations;
+ std::vector<WorkletAnimationId> removed_animations;
+
+ AnimationWorkletInput();
+ ~AnimationWorkletInput();
+
+#if DCHECK_IS_ON()
+ // Verifies all animation states have the expected scope id.
+ bool ValidateScope(int scope_id) const;
+#endif
+ DISALLOW_COPY_AND_ASSIGN(AnimationWorkletInput);
+};
+
+class CC_EXPORT MutatorInputState {
+ public:
MutatorInputState();
~MutatorInputState();
- std::vector<AnimationState> animations;
+ bool IsEmpty() const;
+ void Add(AnimationWorkletInput::AddAndUpdateState&& state);
+ void Update(AnimationWorkletInput::UpdateState&& state);
+ void Remove(WorkletAnimationId worklet_animation_id);
+
+ // Returns input for animation worklet with the given |scope_id| and nullptr
+ // if there is no input.
+ std::unique_ptr<AnimationWorkletInput> TakeWorkletState(int scope_id);
+
+ private:
+ using InputMap =
+ std::unordered_map<int, std::unique_ptr<AnimationWorkletInput>>;
+
+ // Maps a scope id to its associated AnimationWorkletInput instance.
+ // Only contains scope ids for which there is a non-empty input.
+ InputMap inputs_;
+
+ // Returns iterator pointing to the entry in |inputs_| map whose key is id. It
+ // inserts a new entry if none exists.
+ AnimationWorkletInput& EnsureWorkletEntry(int id);
+
+ DISALLOW_COPY_AND_ASSIGN(MutatorInputState);
};
-struct CC_EXPORT MutatorOutputState {
+struct CC_EXPORT AnimationWorkletOutput {
struct CC_EXPORT AnimationState {
- int animation_id = 0;
+ WorkletAnimationId worklet_animation_id;
// The animator effect's local time.
// TODO(majidvp): This assumes each animator has a single output effect
// which does not hold once we state support group effects.
@@ -45,12 +109,16 @@ struct CC_EXPORT MutatorOutputState {
base::TimeDelta local_time;
};
- MutatorOutputState();
- ~MutatorOutputState();
+ AnimationWorkletOutput();
+ ~AnimationWorkletOutput();
std::vector<AnimationState> animations;
};
+// LayerTreeMutatorClient processes worklet outputs individually so we can
+// define mutator output to be the same as animation worklet output.
+using MutatorOutputState = AnimationWorkletOutput;
+
class LayerTreeMutatorClient {
public:
// Called when mutator needs to update its output.
diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h
index 50b8805bc7a..736df815a28 100644
--- a/chromium/cc/trees/layer_tree_settings.h
+++ b/chromium/cc/trees/layer_tree_settings.h
@@ -138,10 +138,6 @@ class CC_EXPORT LayerTreeSettings {
// produces the active tree as its 'sync tree'.
bool commit_to_active_tree = true;
- // Whether to use out of process raster. If true, whenever gpu raster
- // would have been used, out of process gpu raster will be used instead.
- bool enable_oop_rasterization = false;
-
// Whether image animations can be reset to the beginning to avoid skipping
// many frames.
bool enable_image_animation_resync = true;
@@ -160,6 +156,10 @@ class CC_EXPORT LayerTreeSettings {
// Whether a HitTestRegionList should be built from the active layer tree when
// submitting a CompositorFrame.
bool build_hit_test_data = false;
+
+ // When false, sync tokens are expected to be present, and are verified,
+ // before transfering gpu resources to the display compositor.
+ bool delegated_sync_points_required = true;
};
} // namespace cc
diff --git a/chromium/cc/trees/mutator_host.h b/chromium/cc/trees/mutator_host.h
index 18b7fe5118c..586373cc8f2 100644
--- a/chromium/cc/trees/mutator_host.h
+++ b/chromium/cc/trees/mutator_host.h
@@ -61,12 +61,14 @@ class MutatorHost {
// TODO(smcgruer): Once we only tick scroll-based animations on scroll, we
// don't need to pass the scroll tree in here.
virtual bool TickAnimations(base::TimeTicks monotonic_time,
- const ScrollTree& scroll_tree) = 0;
+ const ScrollTree& scroll_tree,
+ bool is_active_tree) = 0;
// Tick animations that depends on scroll offset.
virtual void TickScrollAnimations(base::TimeTicks monotonic_time,
const ScrollTree& scroll_tree) = 0;
virtual bool UpdateAnimationState(bool start_ready_animations,
MutatorEvents* events) = 0;
+ virtual void PromoteScrollTimelinesPendingToActive() = 0;
virtual std::unique_ptr<MutatorEvents> CreateEvents() = 0;
virtual void SetAnimationEvents(std::unique_ptr<MutatorEvents> events) = 0;
diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc
index 3553d91d01a..d94e2fe3c4f 100644
--- a/chromium/cc/trees/property_tree.cc
+++ b/chromium/cc/trees/property_tree.cc
@@ -982,12 +982,13 @@ void EffectTree::TakeCopyRequestsAndTransformToSurface(
// copy of the exact source pixels. If the adjustment to the scale ratio
// would produce out-of-range values, drop the copy request.
if (request->is_scaled() || request->has_result_selection()) {
- float scale_from_x = request->scale_from().x() * surface_rect.width();
- float scale_from_y = request->scale_from().y() * surface_rect.height();
- if (std::isnan(scale_from_x) ||
- !base::IsValueInRangeForNumericType<int>(scale_from_x) ||
- std::isnan(scale_from_y) ||
- !base::IsValueInRangeForNumericType<int>(scale_from_y)) {
+ float scale_from_x_f = request->scale_from().x() * surface_rect.width();
+ float scale_from_y_f =
+ request->scale_from().y() * surface_rect.height();
+ if (std::isnan(scale_from_x_f) ||
+ !base::IsValueInRangeForNumericType<int>(scale_from_x_f) ||
+ std::isnan(scale_from_y_f) ||
+ !base::IsValueInRangeForNumericType<int>(scale_from_y_f)) {
continue;
}
int scale_to_x = request->scale_to().x();
@@ -998,8 +999,15 @@ void EffectTree::TakeCopyRequestsAndTransformToSurface(
.AssignIfValid(&scale_to_y)) {
continue;
}
- request->SetScaleRatio(gfx::Vector2d(gfx::ToRoundedInt(scale_from_x),
- gfx::ToRoundedInt(scale_from_y)),
+ int scale_from_x = gfx::ToRoundedInt(scale_from_x_f);
+ int scale_from_y = gfx::ToRoundedInt(scale_from_y_f);
+ if (scale_from_x <= 0 || scale_from_y <= 0 || scale_to_x <= 0 ||
+ scale_to_y <= 0) {
+ // Transformed scaling ratio became illegal. Drop the request to
+ // provide an empty response.
+ continue;
+ }
+ request->SetScaleRatio(gfx::Vector2d(scale_from_x, scale_from_y),
gfx::Vector2d(scale_to_x, scale_to_y));
}
@@ -1381,6 +1389,18 @@ const SyncedScrollOffset* ScrollTree::GetSyncedScrollOffset(
return it != synced_scroll_offset_map_.end() ? it->second.get() : nullptr;
}
+gfx::Vector2dF ScrollTree::ClampScrollToMaxScrollOffset(
+ ScrollNode* node,
+ LayerTreeImpl* layer_tree_impl) {
+ gfx::ScrollOffset old_offset = current_scroll_offset(node->element_id);
+ gfx::ScrollOffset clamped_offset =
+ ClampScrollOffsetToLimits(old_offset, *node);
+ gfx::Vector2dF delta = clamped_offset.DeltaFrom(old_offset);
+ if (!delta.IsZero())
+ ScrollBy(node, delta, layer_tree_impl);
+ return delta;
+}
+
const gfx::ScrollOffset ScrollTree::current_scroll_offset(ElementId id) const {
if (property_trees()->is_main_thread) {
ScrollOffsetMap::const_iterator it = scroll_offset_map_.find(id);
diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h
index 8cb5abca4aa..39dac923705 100644
--- a/chromium/cc/trees/property_tree.h
+++ b/chromium/cc/trees/property_tree.h
@@ -405,6 +405,8 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> {
void set_currently_scrolling_node(int scroll_node_id);
gfx::Transform ScreenSpaceTransform(int scroll_node_id) const;
+ gfx::Vector2dF ClampScrollToMaxScrollOffset(ScrollNode* node, LayerTreeImpl*);
+
// Returns the current scroll offset. On the main thread this would return the
// value for the LayerTree while on the impl thread this is the current value
// on the active tree.
diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc
index 4aface2581b..a891ce20077 100644
--- a/chromium/cc/trees/property_tree_builder.cc
+++ b/chromium/cc/trees/property_tree_builder.cc
@@ -12,6 +12,7 @@
#include "cc/base/math_util.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
+#include "cc/layers/picture_layer.h"
#include "cc/trees/clip_node.h"
#include "cc/trees/draw_property_utils.h"
#include "cc/trees/effect_node.h"
@@ -59,6 +60,7 @@ class PropertyTreeBuilderContext {
const gfx::Vector2dF& elastic_overscroll,
float page_scale_factor,
const gfx::Transform& device_transform,
+ MutatorHost* mutator_host,
PropertyTrees* property_trees)
: root_layer_(root_layer),
page_scale_layer_(page_scale_layer),
@@ -68,6 +70,7 @@ class PropertyTreeBuilderContext {
elastic_overscroll_(elastic_overscroll),
page_scale_factor_(page_scale_factor),
device_transform_(device_transform),
+ mutator_host_(*mutator_host),
property_trees_(*property_trees),
transform_tree_(property_trees->transform_tree),
clip_tree_(property_trees->clip_tree),
@@ -117,6 +120,7 @@ class PropertyTreeBuilderContext {
const gfx::Vector2dF elastic_overscroll_;
float page_scale_factor_;
const gfx::Transform& device_transform_;
+ MutatorHost& mutator_host_;
PropertyTrees& property_trees_;
TransformTree& transform_tree_;
ClipTree& clip_tree_;
@@ -155,7 +159,7 @@ static LayerImpl* LayerChildAt(LayerImpl* layer, int index) {
}
static Layer* LayerChildAt(Layer* layer, int index) {
- return layer->child_at(index);
+ return layer->children()[index].get();
}
static Layer* ScrollParent(Layer* layer) {
@@ -182,7 +186,7 @@ static inline const FilterOperations& Filters(LayerImpl* layer) {
return layer->test_properties()->filters;
}
-static Layer* MaskLayer(Layer* layer) {
+static PictureLayer* MaskLayer(Layer* layer) {
return layer->mask_layer();
}
@@ -200,58 +204,61 @@ static const gfx::Transform& Transform(LayerImpl* layer) {
// Methods to query state from the AnimationHost ----------------------
template <typename LayerType>
-bool OpacityIsAnimating(LayerType* layer) {
- return layer->GetMutatorHost()->IsAnimatingOpacityProperty(
- layer->element_id(), layer->GetElementTypeForAnimation());
+bool OpacityIsAnimating(const MutatorHost& host, LayerType* layer) {
+ return host.IsAnimatingOpacityProperty(layer->element_id(),
+ layer->GetElementTypeForAnimation());
}
template <typename LayerType>
-bool HasPotentiallyRunningOpacityAnimation(LayerType* layer) {
- return layer->GetMutatorHost()->HasPotentiallyRunningOpacityAnimation(
+bool HasPotentiallyRunningOpacityAnimation(const MutatorHost& host,
+ LayerType* layer) {
+ return host.HasPotentiallyRunningOpacityAnimation(
layer->element_id(), layer->GetElementTypeForAnimation());
}
template <typename LayerType>
-bool FilterIsAnimating(LayerType* layer) {
- return layer->GetMutatorHost()->IsAnimatingFilterProperty(
- layer->element_id(), layer->GetElementTypeForAnimation());
+bool FilterIsAnimating(const MutatorHost& host, LayerType* layer) {
+ return host.IsAnimatingFilterProperty(layer->element_id(),
+ layer->GetElementTypeForAnimation());
}
template <typename LayerType>
-bool HasPotentiallyRunningFilterAnimation(LayerType* layer) {
- return layer->GetMutatorHost()->HasPotentiallyRunningFilterAnimation(
+bool HasPotentiallyRunningFilterAnimation(const MutatorHost& host,
+ LayerType* layer) {
+ return host.HasPotentiallyRunningFilterAnimation(
layer->element_id(), layer->GetElementTypeForAnimation());
}
template <typename LayerType>
-bool TransformIsAnimating(LayerType* layer) {
- return layer->GetMutatorHost()->IsAnimatingTransformProperty(
- layer->element_id(), layer->GetElementTypeForAnimation());
+bool TransformIsAnimating(const MutatorHost& host, LayerType* layer) {
+ return host.IsAnimatingTransformProperty(layer->element_id(),
+ layer->GetElementTypeForAnimation());
}
template <typename LayerType>
-bool HasPotentiallyRunningTransformAnimation(LayerType* layer) {
- return layer->GetMutatorHost()->HasPotentiallyRunningTransformAnimation(
+bool HasPotentiallyRunningTransformAnimation(const MutatorHost& host,
+ LayerType* layer) {
+ return host.HasPotentiallyRunningTransformAnimation(
layer->element_id(), layer->GetElementTypeForAnimation());
}
template <typename LayerType>
-bool HasOnlyTranslationTransforms(LayerType* layer) {
- return layer->GetMutatorHost()->HasOnlyTranslationTransforms(
- layer->element_id(), layer->GetElementTypeForAnimation());
+bool HasOnlyTranslationTransforms(const MutatorHost& host, LayerType* layer) {
+ return host.HasOnlyTranslationTransforms(layer->element_id(),
+ layer->GetElementTypeForAnimation());
}
template <typename LayerType>
-bool AnimationsPreserveAxisAlignment(LayerType* layer) {
- return layer->GetMutatorHost()->AnimationsPreserveAxisAlignment(
- layer->element_id());
+bool AnimationsPreserveAxisAlignment(const MutatorHost& host,
+ LayerType* layer) {
+ return host.AnimationsPreserveAxisAlignment(layer->element_id());
}
template <typename LayerType>
-bool HasAnyAnimationTargetingProperty(LayerType* layer,
+bool HasAnyAnimationTargetingProperty(const MutatorHost& host,
+ LayerType* layer,
TargetProperty::Type property) {
- return layer->GetMutatorHost()->HasAnyAnimationTargetingProperty(
- layer->element_id(), property);
+ return host.HasAnyAnimationTargetingProperty(layer->element_id(), property);
}
// -------------------------------------------------------------------
@@ -295,7 +302,7 @@ static inline int SortingContextId(LayerImpl* layer) {
}
static inline bool Is3dSorted(Layer* layer) {
- return layer->Is3dSorted();
+ return layer->sorting_context_id() != 0;
}
static inline bool Is3dSorted(LayerImpl* layer) {
@@ -393,20 +400,24 @@ bool PropertyTreeBuilderContext<LayerType>::AddTransformNodeIfNeeded(
const bool is_scrollable = layer->scrollable();
const bool is_fixed = PositionConstraint(layer).is_fixed_position();
const bool is_sticky = StickyPositionConstraint(layer).is_sticky;
- const bool is_snapped = layer->IsSnapped();
+ // Scrolling a layer should not move it from being pixel-aligned to moving off
+ // the pixel grid and becoming fuzzy. So always snap scrollable things to the
+ // pixel grid. Layers may also request to be snapped as such.
+ const bool is_snapped =
+ is_scrollable || layer->IsSnappedToPixelGridInTarget();
const bool has_significant_transform =
!Transform(layer).IsIdentityOr2DTranslation();
const bool has_potentially_animated_transform =
- HasPotentiallyRunningTransformAnimation(layer);
+ HasPotentiallyRunningTransformAnimation(mutator_host_, layer);
// A transform node is needed even for a finished animation, since differences
// in the timing of animation state updates can mean that an animation that's
// in the Finished state at tree-building time on the main thread is still in
// the Running state right after commit on the compositor thread.
- const bool has_any_transform_animation =
- HasAnyAnimationTargetingProperty(layer, TargetProperty::TRANSFORM);
+ const bool has_any_transform_animation = HasAnyAnimationTargetingProperty(
+ mutator_host_, layer, TargetProperty::TRANSFORM);
const bool has_surface = created_render_surface;
@@ -433,6 +444,16 @@ bool PropertyTreeBuilderContext<LayerType>::AddTransformNodeIfNeeded(
source_offset = LayerParent(layer)->offset_to_transform_parent();
}
+ // For a container of fixed position descendants, define for them their
+ // fixed-position transform parent as being this layer's transform node, or
+ // its transform parent's node if this layer won't have a node of its own.
+ //
+ // But if this layer is scrollable, then we point fixed position descendants
+ // to not be affected by this layer as it changes its scroll offset during
+ // a compositor thread scroll. We do this by pointing them to the direct
+ // parent of this layer, which acts as a proxy for this layer, without
+ // including scrolling, based on the assumption this layer has no transform
+ // itself when scrollable.
if (IsContainerForFixedPositionLayers(layer) || is_root) {
data_for_children->affected_by_outer_viewport_bounds_delta =
layer->IsResizedByBrowserControls();
@@ -459,9 +480,9 @@ bool PropertyTreeBuilderContext<LayerType>::AddTransformNodeIfNeeded(
&to_parent);
source_to_parent = to_parent.To2dTranslation();
}
- layer->set_offset_to_transform_parent(source_offset + source_to_parent +
- local_offset);
- layer->set_should_flatten_transform_from_property_tree(
+ layer->SetOffsetToTransformParent(source_offset + source_to_parent +
+ local_offset);
+ layer->SetShouldFlattenScreenSpaceTransformFromPropertyTree(
data_from_ancestor.should_flatten);
layer->SetTransformTreeIndex(parent_index);
return false;
@@ -496,10 +517,10 @@ bool PropertyTreeBuilderContext<LayerType>::AddTransformNodeIfNeeded(
ShouldFlattenTransform(layer) || has_surface;
node->has_potential_animation = has_potentially_animated_transform;
- node->is_currently_animating = TransformIsAnimating(layer);
+ node->is_currently_animating = TransformIsAnimating(mutator_host_, layer);
if (has_potentially_animated_transform) {
node->has_only_translation_animations =
- HasOnlyTranslationTransforms(layer);
+ HasOnlyTranslationTransforms(mutator_host_, layer);
}
float post_local_scale_factor = 1.0f;
@@ -593,21 +614,23 @@ bool PropertyTreeBuilderContext<LayerType>::AddTransformNodeIfNeeded(
node->needs_local_transform_update = true;
transform_tree_.UpdateTransforms(node->id);
- layer->set_offset_to_transform_parent(gfx::Vector2dF());
+ layer->SetOffsetToTransformParent(gfx::Vector2dF());
// Flattening (if needed) will be handled by |node|.
- layer->set_should_flatten_transform_from_property_tree(false);
+ layer->SetShouldFlattenScreenSpaceTransformFromPropertyTree(false);
return true;
}
-static inline bool HasPotentialOpacityAnimation(Layer* layer) {
- return HasPotentiallyRunningOpacityAnimation(layer) ||
+static inline bool HasPotentialOpacityAnimation(const MutatorHost& host,
+ Layer* layer) {
+ return HasPotentiallyRunningOpacityAnimation(host, layer) ||
layer->OpacityCanAnimateOnImplThread();
}
-static inline bool HasPotentialOpacityAnimation(LayerImpl* layer) {
- return HasPotentiallyRunningOpacityAnimation(layer) ||
+static inline bool HasPotentialOpacityAnimation(const MutatorHost& host,
+ LayerImpl* layer) {
+ return HasPotentiallyRunningOpacityAnimation(host, layer) ||
layer->test_properties()->opacity_can_animate;
}
@@ -749,7 +772,8 @@ static inline bool PropertyChanged(LayerImpl* layer) {
}
template <typename LayerType>
-bool ShouldCreateRenderSurface(LayerType* layer,
+bool ShouldCreateRenderSurface(const MutatorHost& mutator_host,
+ LayerType* layer,
gfx::Transform current_transform,
bool animation_axis_aligned) {
const bool preserves_2d_axis_alignment =
@@ -775,7 +799,7 @@ bool ShouldCreateRenderSurface(LayerType* layer,
// If the layer will use a CSS filter. In this case, the animation
// will start and add a filter to this layer, so it needs a surface.
- if (HasPotentiallyRunningFilterAnimation(layer)) {
+ if (HasPotentiallyRunningFilterAnimation(mutator_host, layer)) {
return true;
}
@@ -821,8 +845,9 @@ bool ShouldCreateRenderSurface(LayerType* layer,
num_descendants_that_draw_content > 0 &&
(layer->DrawsContent() || num_descendants_that_draw_content > 1);
- bool may_have_transparency = EffectiveOpacity(layer) != 1.f ||
- HasPotentiallyRunningOpacityAnimation(layer);
+ bool may_have_transparency =
+ EffectiveOpacity(layer) != 1.f ||
+ HasPotentiallyRunningOpacityAnimation(mutator_host, layer);
if (may_have_transparency && ShouldFlattenTransform(layer) &&
at_least_two_layers_in_subtree_draw_content) {
TRACE_EVENT_INSTANT0(
@@ -912,21 +937,22 @@ bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded(
const bool is_root = !LayerParent(layer);
const bool has_transparency = EffectiveOpacity(layer) != 1.f;
const bool has_potential_opacity_animation =
- HasPotentialOpacityAnimation(layer);
+ HasPotentialOpacityAnimation(mutator_host_, layer);
const bool has_potential_filter_animation =
- HasPotentiallyRunningFilterAnimation(layer);
+ HasPotentiallyRunningFilterAnimation(mutator_host_, layer);
data_for_children->animation_axis_aligned_since_render_target &=
- AnimationsPreserveAxisAlignment(layer);
+ AnimationsPreserveAxisAlignment(mutator_host_, layer);
data_for_children->compound_transform_since_render_target *= Transform(layer);
const bool should_create_render_surface = ShouldCreateRenderSurface(
- layer, data_for_children->compound_transform_since_render_target,
+ mutator_host_, layer,
+ data_for_children->compound_transform_since_render_target,
data_for_children->animation_axis_aligned_since_render_target);
bool not_axis_aligned_since_last_clip =
data_from_ancestor.not_axis_aligned_since_last_clip
? true
- : !AnimationsPreserveAxisAlignment(layer) ||
+ : !AnimationsPreserveAxisAlignment(mutator_host_, layer) ||
!Transform(layer).Preserves2dAxisAlignment();
// A non-axis aligned clip may need a render surface. So, we create an effect
// node.
@@ -963,8 +989,9 @@ bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded(
node->has_potential_filter_animation = has_potential_filter_animation;
node->double_sided = DoubleSided(layer);
node->subtree_hidden = HideLayerAndSubtree(layer);
- node->is_currently_animating_opacity = OpacityIsAnimating(layer);
- node->is_currently_animating_filter = FilterIsAnimating(layer);
+ node->is_currently_animating_opacity =
+ OpacityIsAnimating(mutator_host_, layer);
+ node->is_currently_animating_filter = FilterIsAnimating(mutator_host_, layer);
node->effect_changed = PropertyChanged(layer);
node->subtree_has_copy_request = SubtreeHasCopyRequest(layer);
node->closest_ancestor_with_cached_render_surface_id =
@@ -1118,7 +1145,8 @@ void PropertyTreeBuilderContext<LayerType>::AddScrollNodeIfNeeded(
node.bounds = layer->bounds();
node.container_bounds = layer->scroll_container_bounds();
node.offset_to_transform_parent = layer->offset_to_transform_parent();
- node.should_flatten = layer->should_flatten_transform_from_property_tree();
+ node.should_flatten =
+ layer->should_flatten_screen_space_transform_from_property_tree();
node.user_scrollable_horizontal = UserScrollableHorizontal(layer);
node.user_scrollable_vertical = UserScrollableVertical(layer);
node.element_id = layer->element_id();
@@ -1200,7 +1228,6 @@ void PropertyTreeBuilderContext<LayerType>::BuildPropertyTreesInternal(
bool created_render_surface =
AddEffectNodeIfNeeded(data_from_parent, layer, &data_for_children);
-
bool created_transform_node = AddTransformNodeIfNeeded(
data_from_parent, layer, created_render_surface, &data_for_children);
SetHasTransformNode(layer, created_transform_node);
@@ -1215,7 +1242,7 @@ void PropertyTreeBuilderContext<LayerType>::BuildPropertyTreesInternal(
bool not_axis_aligned_since_last_clip =
data_from_parent.not_axis_aligned_since_last_clip
? true
- : !AnimationsPreserveAxisAlignment(layer) ||
+ : !AnimationsPreserveAxisAlignment(mutator_host_, layer) ||
!Transform(layer).Preserves2dAxisAlignment();
bool has_non_axis_aligned_clip =
not_axis_aligned_since_last_clip && LayerClipsSubtree(layer);
@@ -1244,7 +1271,7 @@ void PropertyTreeBuilderContext<LayerType>::BuildPropertyTreesInternal(
if (MaskLayer(layer)) {
MaskLayer(layer)->set_property_tree_sequence_number(
property_trees_.sequence_number);
- MaskLayer(layer)->set_offset_to_transform_parent(
+ MaskLayer(layer)->SetOffsetToTransformParent(
layer->offset_to_transform_parent());
MaskLayer(layer)->SetTransformTreeIndex(layer->transform_tree_index());
MaskLayer(layer)->SetClipTreeIndex(layer->clip_tree_index());
@@ -1284,14 +1311,32 @@ void PropertyTreeBuilderContext<LayerType>::BuildPropertyTrees(
const gfx::Rect& viewport,
SkColor root_background_color) const {
if (!property_trees_.needs_rebuild) {
- draw_property_utils::UpdatePageScaleFactor(
- &property_trees_, page_scale_layer_, page_scale_factor_,
- device_scale_factor, device_transform_);
+ bool page_scale_is_root_layer = page_scale_layer_ == root_layer_;
+ if (page_scale_layer_) {
+ DCHECK_GE(page_scale_layer_->transform_tree_index(),
+ TransformTree::kRootNodeId);
+ TransformNode* node = property_trees_.transform_tree.Node(
+ page_scale_layer_->transform_tree_index());
+
+ // When the page scale layer is also the root layer, the node should also
+ // store the combined scale factor and not just the page scale factor.
+ float device_scale_factor_for_page_scale_node = 1.f;
+ gfx::Transform device_transform_for_page_scale_node;
+ if (page_scale_is_root_layer) {
+ device_transform_for_page_scale_node = device_transform_;
+ device_scale_factor_for_page_scale_node = device_scale_factor;
+ }
+
+ draw_property_utils::UpdatePageScaleFactor(
+ &property_trees_, node, page_scale_factor_,
+ device_scale_factor_for_page_scale_node,
+ device_transform_for_page_scale_node);
+ }
draw_property_utils::UpdateElasticOverscroll(
&property_trees_, overscroll_elasticity_layer_, elastic_overscroll_);
clip_tree_.SetViewportClip(gfx::RectF(viewport));
float page_scale_factor_for_root =
- page_scale_layer_ == root_layer_ ? page_scale_factor_ : 1.f;
+ page_scale_is_root_layer ? page_scale_factor_ : 1.f;
transform_tree_.SetRootTransformsAndScales(
device_scale_factor, page_scale_factor_for_root, device_transform_,
root_layer_->position());
@@ -1399,7 +1444,8 @@ void PropertyTreeBuilder::BuildPropertyTrees(
PropertyTreeBuilderContext<Layer>(
root_layer, page_scale_layer, inner_viewport_scroll_layer,
outer_viewport_scroll_layer, overscroll_elasticity_layer,
- elastic_overscroll, page_scale_factor, device_transform, property_trees)
+ elastic_overscroll, page_scale_factor, device_transform,
+ root_layer->layer_tree_host()->mutator_host(), property_trees)
.BuildPropertyTrees(device_scale_factor, viewport, color);
#if DCHECK_IS_ON()
for (auto* layer : AllLayerRange(root_layer))
@@ -1438,7 +1484,8 @@ void PropertyTreeBuilder::BuildPropertyTrees(
PropertyTreeBuilderContext<LayerImpl>(
root_layer, page_scale_layer, inner_viewport_scroll_layer,
outer_viewport_scroll_layer, overscroll_elasticity_layer,
- elastic_overscroll, page_scale_factor, device_transform, property_trees)
+ elastic_overscroll, page_scale_factor, device_transform,
+ root_layer->layer_tree_impl()->mutator_host(), property_trees)
.BuildPropertyTrees(device_scale_factor, viewport, color);
property_trees->effect_tree.CreateOrReuseRenderSurfaces(
&render_surfaces, root_layer->layer_tree_impl());
diff --git a/chromium/cc/trees/property_tree_unittest.cc b/chromium/cc/trees/property_tree_unittest.cc
index 1c0c37692fc..7935b599b40 100644
--- a/chromium/cc/trees/property_tree_unittest.cc
+++ b/chromium/cc/trees/property_tree_unittest.cc
@@ -11,6 +11,7 @@
#include "cc/trees/effect_node.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/transform_node.h"
+#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
@@ -529,5 +530,138 @@ TEST(PropertyTreeTest, SingularTransformSnapTest) {
EXPECT_NE(to_target, rounded);
}
+// Tests that CopyOutputRequests are transformed by the EffectTree, such that
+// assumptions the original requestor made about coordinate spaces remains true
+// after the EffectTree transforms the requests.
+TEST(EffectTreeTest, CopyOutputRequestsAreTransformed) {
+ using viz::CopyOutputRequest;
+
+ PropertyTrees property_trees;
+
+ TransformTree& transform_tree = property_trees.transform_tree;
+ TransformNode contents_root;
+ contents_root.local.Scale(2, 2);
+ contents_root.source_node_id = 0;
+ contents_root.id = transform_tree.Insert(contents_root, 0);
+ transform_tree.UpdateTransforms(contents_root.id);
+
+ EffectTree& effect_tree = property_trees.effect_tree;
+ EffectNode effect_node;
+ effect_node.has_render_surface = true;
+ effect_node.has_copy_request = true;
+ effect_node.transform_id = contents_root.id;
+ effect_node.id = effect_tree.Insert(effect_node, 0);
+ effect_tree.UpdateEffects(effect_node.id);
+
+ // A CopyOutputRequest with only its area set should be transformed into one
+ // that is scaled by two. In this case, by specifying no result selection, the
+ // requestor has indicated they want all the pixels, regardless of size. Thus,
+ // the result selection and scale ratio should still be unset in the
+ // transformed request to carry-over those semantics.
+ auto request_in = CopyOutputRequest::CreateStubForTesting();
+ request_in->set_area(gfx::Rect(10, 20, 30, 40));
+ effect_tree.AddCopyRequest(effect_node.id, std::move(request_in));
+ std::vector<std::unique_ptr<CopyOutputRequest>> requests_out;
+ effect_tree.TakeCopyRequestsAndTransformToSurface(effect_node.id,
+ &requests_out);
+ ASSERT_EQ(1u, requests_out.size());
+ const CopyOutputRequest* request_out = requests_out.front().get();
+ ASSERT_TRUE(request_out->has_area());
+ EXPECT_EQ(gfx::Rect(20, 40, 60, 80), request_out->area());
+ EXPECT_FALSE(request_out->has_result_selection());
+ EXPECT_FALSE(request_out->is_scaled());
+
+ // A CopyOutputRequest with its area and result selection set, but no scaling
+ // specified, should be transformed into one that has its area scaled by two,
+ // but now also includes a scale ratio of 1/2. This is because the requestor
+ // had originally specified a result selection under old assumptions about the
+ // source coordinate system.
+ request_in = CopyOutputRequest::CreateStubForTesting();
+ request_in->set_area(gfx::Rect(10, 20, 30, 40));
+ request_in->set_result_selection(gfx::Rect(1, 2, 3, 4));
+ effect_tree.AddCopyRequest(effect_node.id, std::move(request_in));
+ requests_out.clear();
+ effect_tree.TakeCopyRequestsAndTransformToSurface(effect_node.id,
+ &requests_out);
+ ASSERT_EQ(1u, requests_out.size());
+ request_out = requests_out.front().get();
+ ASSERT_TRUE(request_out->has_area());
+ EXPECT_EQ(gfx::Rect(20, 40, 60, 80), request_out->area());
+ ASSERT_TRUE(request_out->has_result_selection());
+ EXPECT_EQ(gfx::Rect(1, 2, 3, 4), request_out->result_selection());
+ ASSERT_TRUE(request_out->is_scaled());
+ EXPECT_NEAR(0.5f,
+ static_cast<float>(request_out->scale_to().x()) /
+ request_out->scale_from().x(),
+ 0.000001);
+ EXPECT_NEAR(0.5f,
+ static_cast<float>(request_out->scale_to().y()) /
+ request_out->scale_from().y(),
+ 0.000001);
+
+ // A CopyOutputRequest with all three of: area, result selection, and scale
+ // ratio; should be transformed into one with an updated area and combined
+ // scale ratio.
+ request_in = CopyOutputRequest::CreateStubForTesting();
+ request_in->set_area(gfx::Rect(10, 20, 30, 40));
+ request_in->set_result_selection(gfx::Rect(1, 2, 3, 4));
+ // Request has a 3X scale in X, and 5X scale in Y.
+ request_in->SetScaleRatio(gfx::Vector2d(1, 1), gfx::Vector2d(3, 5));
+ effect_tree.AddCopyRequest(effect_node.id, std::move(request_in));
+ requests_out.clear();
+ effect_tree.TakeCopyRequestsAndTransformToSurface(effect_node.id,
+ &requests_out);
+ ASSERT_EQ(1u, requests_out.size());
+ request_out = requests_out.front().get();
+ ASSERT_TRUE(request_out->has_area());
+ EXPECT_EQ(gfx::Rect(20, 40, 60, 80), request_out->area());
+ ASSERT_TRUE(request_out->has_result_selection());
+ EXPECT_EQ(gfx::Rect(1, 2, 3, 4), request_out->result_selection());
+ ASSERT_TRUE(request_out->is_scaled());
+ EXPECT_NEAR(3.0f / 2.0f,
+ static_cast<float>(request_out->scale_to().x()) /
+ request_out->scale_from().x(),
+ 0.000001);
+ EXPECT_NEAR(5.0f / 2.0f,
+ static_cast<float>(request_out->scale_to().y()) /
+ request_out->scale_from().y(),
+ 0.000001);
+}
+
+// Tests that a good CopyOutputRequest which becomes transformed into an invalid
+// one is dropped (i.e., the requestor would get an "empty response" in its
+// result callback). The scaling transform in this test is so extreme that it
+// would result in an illegal adjustment to the CopyOutputRequest's scale ratio.
+TEST(EffectTreeTest, CopyOutputRequestsThatBecomeIllegalAreDropped) {
+ using viz::CopyOutputRequest;
+
+ PropertyTrees property_trees;
+
+ TransformTree& transform_tree = property_trees.transform_tree;
+ TransformNode contents_root;
+ contents_root.local.Scale(1.0f / 1.0e9f, 1.0f / 1.0e9f);
+ contents_root.source_node_id = 0;
+ contents_root.id = transform_tree.Insert(contents_root, 0);
+ transform_tree.UpdateTransforms(contents_root.id);
+
+ EffectTree& effect_tree = property_trees.effect_tree;
+ EffectNode effect_node;
+ effect_node.has_render_surface = true;
+ effect_node.has_copy_request = true;
+ effect_node.transform_id = contents_root.id;
+ effect_node.id = effect_tree.Insert(effect_node, 0);
+ effect_tree.UpdateEffects(effect_node.id);
+
+ auto request_in = CopyOutputRequest::CreateStubForTesting();
+ request_in->set_area(gfx::Rect(10, 20, 30, 40));
+ request_in->set_result_selection(gfx::Rect(1, 2, 3, 4));
+ request_in->SetScaleRatio(gfx::Vector2d(1, 1), gfx::Vector2d(3, 5));
+ effect_tree.AddCopyRequest(effect_node.id, std::move(request_in));
+ std::vector<std::unique_ptr<CopyOutputRequest>> requests_out;
+ effect_tree.TakeCopyRequestsAndTransformToSurface(effect_node.id,
+ &requests_out);
+ EXPECT_TRUE(requests_out.empty());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h
index 5ae47500340..42d4fd2975c 100644
--- a/chromium/cc/trees/proxy.h
+++ b/chromium/cc/trees/proxy.h
@@ -50,14 +50,16 @@ class CC_EXPORT Proxy {
virtual void SetNeedsRedraw(const gfx::Rect& damage_rect) = 0;
virtual void SetNextCommitWaitsForActivation() = 0;
+ // Returns true if an animate or commit has been requested, and hasn't
+ // completed yet.
+ virtual bool RequestedAnimatePending() = 0;
+
virtual void NotifyInputThrottledUntilCommit() = 0;
// Defers commits until it is reset. It is only supported when using a
// scheduler.
virtual void SetDeferCommits(bool defer_commits) = 0;
- virtual void MainThreadHasStoppedFlinging() = 0;
-
virtual bool CommitRequested() const = 0;
// Must be called before using the proxy.
@@ -80,7 +82,7 @@ class CC_EXPORT Proxy {
virtual void SetURLForUkm(const GURL& url) = 0;
- virtual void ClearHistoryOnNavigation() = 0;
+ virtual void ClearHistory() = 0;
virtual void SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) = 0;
diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc
index 06b051455ed..f750ec063f8 100644
--- a/chromium/cc/trees/proxy_impl.cc
+++ b/chromium/cc/trees/proxy_impl.cc
@@ -27,6 +27,7 @@
#include "components/viz/common/gpu/context_provider.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "ui/gfx/presentation_feedback.h"
namespace cc {
@@ -136,7 +137,7 @@ void ProxyImpl::InitializeLayerTreeFrameSinkOnImpl(
proxy_main_frame_sink_bound_weak_ptr_ = proxy_main_frame_sink_bound_weak_ptr;
LayerTreeHostImpl* host_impl = host_impl_.get();
- bool success = host_impl->InitializeRenderer(layer_tree_frame_sink);
+ bool success = host_impl->InitializeFrameSink(layer_tree_frame_sink);
MainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&ProxyMain::DidInitializeLayerTreeFrameSink,
proxy_main_weak_ptr_, success));
@@ -144,11 +145,6 @@ void ProxyImpl::InitializeLayerTreeFrameSinkOnImpl(
scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
}
-void ProxyImpl::MainThreadHasStoppedFlingingOnImpl() {
- DCHECK(IsImplThread());
- host_impl_->MainThreadHasStoppedFlinging();
-}
-
void ProxyImpl::SetInputThrottledUntilCommitOnImpl(bool is_throttled) {
DCHECK(IsImplThread());
if (is_throttled == input_throttled_until_commit_)
@@ -463,9 +459,11 @@ void ProxyImpl::DidCompletePageScaleAnimationOnImplThread() {
proxy_main_weak_ptr_));
}
-void ProxyImpl::OnDrawForLayerTreeFrameSink(bool resourceless_software_draw) {
+void ProxyImpl::OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,
+ bool skip_draw) {
DCHECK(IsImplThread());
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw);
+ scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
+ skip_draw);
}
void ProxyImpl::NeedsImplSideInvalidation(bool needs_first_draw_on_activation) {
@@ -479,14 +477,13 @@ void ProxyImpl::NotifyImageDecodeRequestFinished() {
}
void ProxyImpl::DidPresentCompositorFrameOnImplThread(
- const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) {
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback) {
MainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&ProxyMain::DidPresentCompositorFrame,
- proxy_main_weak_ptr_, source_frames, time,
- refresh, flags));
+ proxy_main_weak_ptr_, frame_token,
+ std::move(callbacks), feedback));
}
bool ProxyImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
@@ -611,10 +608,10 @@ void ProxyImpl::ScheduledActionPrepareTiles() {
host_impl_->PrepareTiles();
}
-void ProxyImpl::ScheduledActionInvalidateLayerTreeFrameSink() {
+void ProxyImpl::ScheduledActionInvalidateLayerTreeFrameSink(bool needs_redraw) {
TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionInvalidateLayerTreeFrameSink");
DCHECK(IsImplThread());
- host_impl_->InvalidateLayerTreeFrameSink();
+ host_impl_->InvalidateLayerTreeFrameSink(needs_redraw);
}
void ProxyImpl::ScheduledActionPerformImplSideInvalidation() {
@@ -727,10 +724,10 @@ void ProxyImpl::SetURLForUkm(const GURL& url) {
host_impl_->ukm_manager()->SetSourceURL(url);
}
-void ProxyImpl::ClearHistoryOnNavigation() {
+void ProxyImpl::ClearHistory() {
DCHECK(IsImplThread());
DCHECK(IsMainThreadBlocked());
- scheduler_->ClearHistoryOnNavigation();
+ scheduler_->ClearHistory();
}
void ProxyImpl::SetRenderFrameObserver(
diff --git a/chromium/cc/trees/proxy_impl.h b/chromium/cc/trees/proxy_impl.h
index 467f0e616d8..a6b9fa279b5 100644
--- a/chromium/cc/trees/proxy_impl.h
+++ b/chromium/cc/trees/proxy_impl.h
@@ -38,7 +38,6 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
LayerTreeFrameSink* layer_tree_frame_sink,
base::WeakPtr<ProxyMain> proxy_main_frame_sink_bound_weak_ptr);
void InitializeMutatorOnImpl(std::unique_ptr<LayerTreeMutator> mutator);
- void MainThreadHasStoppedFlingingOnImpl();
void SetInputThrottledUntilCommitOnImpl(bool is_throttled);
void SetDeferCommitsOnImpl(bool defer_commits) const;
void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect);
@@ -55,7 +54,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
base::TimeTicks main_thread_start_time,
bool hold_commit_for_activation);
void SetURLForUkm(const GURL& url);
- void ClearHistoryOnNavigation();
+ void ClearHistory();
void SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer);
@@ -97,14 +96,14 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
void WillPrepareTiles() override;
void DidPrepareTiles() override;
void DidCompletePageScaleAnimationOnImplThread() override;
- void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw) override;
+ void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,
+ bool skip_draw) override;
void NeedsImplSideInvalidation(bool needs_first_draw_on_activation) override;
void NotifyImageDecodeRequestFinished() override;
void DidPresentCompositorFrameOnImplThread(
- const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) override;
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback) override;
// SchedulerClient implementation
bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override;
@@ -118,7 +117,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
void ScheduledActionActivateSyncTree() override;
void ScheduledActionBeginLayerTreeFrameSinkCreation() override;
void ScheduledActionPrepareTiles() override;
- void ScheduledActionInvalidateLayerTreeFrameSink() override;
+ void ScheduledActionInvalidateLayerTreeFrameSink(bool needs_redraw) override;
void ScheduledActionPerformImplSideInvalidation() override;
void SendBeginMainFrameNotExpectedSoon() override;
void ScheduledActionBeginMainFrameNotExpectedUntil(
diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc
index 668e674e30d..334c323e297 100644
--- a/chromium/cc/trees/proxy_main.cc
+++ b/chromium/cc/trees/proxy_main.cc
@@ -300,7 +300,7 @@ void ProxyMain::BeginMainFrame(
// commit.
ui::LatencyInfo new_latency_info(ui::SourceEventType::FRAME);
new_latency_info.AddLatencyNumberWithTimestamp(
- ui::LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT, 0,
+ ui::LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT,
begin_main_frame_state->begin_frame_args.frame_time, 1);
layer_tree_host_->QueueSwapPromise(
std::make_unique<LatencyInfoSwapPromise>(new_latency_info));
@@ -331,12 +331,12 @@ void ProxyMain::BeginMainFrame(
layer_tree_host_->DidBeginMainFrame();
}
-void ProxyMain::DidPresentCompositorFrame(const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) {
- layer_tree_host_->DidPresentCompositorFrame(source_frames, time, refresh,
- flags);
+void ProxyMain::DidPresentCompositorFrame(
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback) {
+ layer_tree_host_->DidPresentCompositorFrame(frame_token, std::move(callbacks),
+ feedback);
}
bool ProxyMain::IsStarted() const {
@@ -418,6 +418,10 @@ void ProxyMain::SetNextCommitWaitsForActivation() {
commit_waits_for_activation_ = true;
}
+bool ProxyMain::RequestedAnimatePending() {
+ return max_requested_pipeline_stage_ >= ANIMATE_PIPELINE_STAGE;
+}
+
void ProxyMain::NotifyInputThrottledUntilCommit() {
DCHECK(IsMainThread());
ImplThreadTaskRunner()->PostTask(
@@ -450,13 +454,6 @@ bool ProxyMain::CommitRequested() const {
max_requested_pipeline_stage_ >= COMMIT_PIPELINE_STAGE;
}
-void ProxyMain::MainThreadHasStoppedFlinging() {
- DCHECK(IsMainThread());
- ImplThreadTaskRunner()->PostTask(
- FROM_HERE, base::BindOnce(&ProxyImpl::MainThreadHasStoppedFlingingOnImpl,
- base::Unretained(proxy_impl_.get())));
-}
-
void ProxyMain::Start() {
DCHECK(IsMainThread());
DCHECK(layer_tree_host_->IsThreaded());
@@ -597,11 +594,11 @@ void ProxyMain::SetURLForUkm(const GURL& url) {
base::Unretained(proxy_impl_.get()), url));
}
-void ProxyMain::ClearHistoryOnNavigation() {
+void ProxyMain::ClearHistory() {
// Must only be called from the impl thread during commit.
DCHECK(task_runner_provider_->IsImplThread());
DCHECK(task_runner_provider_->IsMainThreadBlocked());
- proxy_impl_->ClearHistoryOnNavigation();
+ proxy_impl_->ClearHistory();
}
void ProxyMain::SetRenderFrameObserver(
diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h
index b280ca948ae..9e32ce2d311 100644
--- a/chromium/cc/trees/proxy_main.h
+++ b/chromium/cc/trees/proxy_main.h
@@ -52,10 +52,10 @@ class CC_EXPORT ProxyMain : public Proxy {
void DidCompletePageScaleAnimation();
void BeginMainFrame(
std::unique_ptr<BeginMainFrameAndCommitState> begin_main_frame_state);
- void DidPresentCompositorFrame(const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags);
+ void DidPresentCompositorFrame(
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback);
CommitPipelineStage max_requested_pipeline_stage() const {
return max_requested_pipeline_stage_;
@@ -79,10 +79,10 @@ class CC_EXPORT ProxyMain : public Proxy {
void SetNeedsCommit() override;
void SetNeedsRedraw(const gfx::Rect& damage_rect) override;
void SetNextCommitWaitsForActivation() override;
+ bool RequestedAnimatePending() override;
void NotifyInputThrottledUntilCommit() override;
void SetDeferCommits(bool defer_commits) override;
bool CommitRequested() const override;
- void MainThreadHasStoppedFlinging() override;
void Start() override;
void Stop() override;
bool SupportsImplScrolling() const override;
@@ -94,7 +94,7 @@ class CC_EXPORT ProxyMain : public Proxy {
bool animate) override;
void RequestBeginMainFrameNotExpected(bool new_state) override;
void SetURLForUkm(const GURL& url) override;
- void ClearHistoryOnNavigation() override;
+ void ClearHistory() override;
void SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) override;
diff --git a/chromium/cc/trees/render_frame_metadata.cc b/chromium/cc/trees/render_frame_metadata.cc
index 5678f5c8987..82340bb7fff 100644
--- a/chromium/cc/trees/render_frame_metadata.cc
+++ b/chromium/cc/trees/render_frame_metadata.cc
@@ -4,6 +4,8 @@
#include "cc/trees/render_frame_metadata.h"
+#include "build/build_config.h"
+
namespace cc {
RenderFrameMetadata::RenderFrameMetadata() = default;
@@ -15,23 +17,6 @@ RenderFrameMetadata::RenderFrameMetadata(RenderFrameMetadata&& other) = default;
RenderFrameMetadata::~RenderFrameMetadata() {}
-// static
-bool RenderFrameMetadata::HasAlwaysUpdateMetadataChanged(
- const RenderFrameMetadata& rfm1,
- const RenderFrameMetadata& rfm2) {
- return rfm1.root_background_color != rfm2.root_background_color ||
- rfm1.is_scroll_offset_at_top != rfm2.is_scroll_offset_at_top ||
- rfm1.selection != rfm2.selection ||
- rfm1.is_mobile_optimized != rfm2.is_mobile_optimized ||
- rfm1.device_scale_factor != rfm2.device_scale_factor ||
- rfm1.viewport_size_in_pixels != rfm2.viewport_size_in_pixels ||
- rfm1.local_surface_id != rfm2.local_surface_id ||
- rfm1.top_controls_height != rfm2.top_controls_height ||
- rfm1.top_controls_shown_ratio != rfm2.top_controls_shown_ratio ||
- rfm1.bottom_controls_height != rfm2.bottom_controls_height ||
- rfm1.bottom_controls_shown_ratio != rfm2.bottom_controls_shown_ratio;
-}
-
RenderFrameMetadata& RenderFrameMetadata::operator=(
const RenderFrameMetadata&) = default;
@@ -46,11 +31,20 @@ bool RenderFrameMetadata::operator==(const RenderFrameMetadata& other) const {
is_mobile_optimized == other.is_mobile_optimized &&
device_scale_factor == other.device_scale_factor &&
viewport_size_in_pixels == other.viewport_size_in_pixels &&
- local_surface_id == other.local_surface_id &&
+ page_scale_factor == other.page_scale_factor &&
+#if defined(OS_ANDROID)
top_controls_height == other.top_controls_height &&
top_controls_shown_ratio == other.top_controls_shown_ratio &&
bottom_controls_height == other.bottom_controls_height &&
- bottom_controls_shown_ratio == other.bottom_controls_shown_ratio;
+ bottom_controls_shown_ratio == other.bottom_controls_shown_ratio &&
+ min_page_scale_factor == other.min_page_scale_factor &&
+ max_page_scale_factor == other.max_page_scale_factor &&
+ root_overflow_y_hidden == other.root_overflow_y_hidden &&
+ scrollable_viewport_size == other.scrollable_viewport_size &&
+ root_layer_size == other.root_layer_size &&
+ has_transparent_background == other.has_transparent_background &&
+#endif
+ local_surface_id == other.local_surface_id;
}
bool RenderFrameMetadata::operator!=(const RenderFrameMetadata& other) const {
diff --git a/chromium/cc/trees/render_frame_metadata.h b/chromium/cc/trees/render_frame_metadata.h
index d07d7d4bfc6..e86ff1efe9c 100644
--- a/chromium/cc/trees/render_frame_metadata.h
+++ b/chromium/cc/trees/render_frame_metadata.h
@@ -6,11 +6,13 @@
#define CC_TREES_RENDER_FRAME_METADATA_H_
#include "base/optional.h"
+#include "build/build_config.h"
#include "cc/cc_export.h"
#include "components/viz/common/quads/selection.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/selection_bound.h"
@@ -23,12 +25,6 @@ class CC_EXPORT RenderFrameMetadata {
RenderFrameMetadata(RenderFrameMetadata&& other);
~RenderFrameMetadata();
- // Certain fields should always have their changes reported. This will return
- // true when there is a difference between |rfm1| and |rfm2| for those fields.
- // These fields have a low frequency rate of change.
- static bool HasAlwaysUpdateMetadataChanged(const RenderFrameMetadata& rfm1,
- const RenderFrameMetadata& rfm2);
-
RenderFrameMetadata& operator=(const RenderFrameMetadata&);
RenderFrameMetadata& operator=(RenderFrameMetadata&& other);
bool operator==(const RenderFrameMetadata& other) const;
@@ -67,6 +63,9 @@ class CC_EXPORT RenderFrameMetadata {
// The last viz::LocalSurfaceId used to submit a CompositorFrame.
base::Optional<viz::LocalSurfaceId> local_surface_id;
+ float page_scale_factor = 1.f;
+
+#if defined(OS_ANDROID)
// Used to position the Android location top bar and page content, whose
// precise position is computed by the renderer compositor.
float top_controls_height = 0.f;
@@ -76,6 +75,20 @@ class CC_EXPORT RenderFrameMetadata {
// renderer compositor.
float bottom_controls_height = 0.f;
float bottom_controls_shown_ratio = 0.f;
+
+ // These limits can be used together with the scroll/scale fields above to
+ // determine if scrolling/scaling in a particular direction is possible.
+ float min_page_scale_factor = 0.f;
+ float max_page_scale_factor = 0.f;
+ bool root_overflow_y_hidden = false;
+
+ gfx::SizeF scrollable_viewport_size;
+ gfx::SizeF root_layer_size;
+
+ // Returns whether the root RenderPass of the CompositorFrame has a
+ // transparent background color.
+ bool has_transparent_background = false;
+#endif
};
} // namespace cc
diff --git a/chromium/cc/trees/render_frame_metadata_observer.h b/chromium/cc/trees/render_frame_metadata_observer.h
index 90491d70ab9..69037c5ef5b 100644
--- a/chromium/cc/trees/render_frame_metadata_observer.h
+++ b/chromium/cc/trees/render_frame_metadata_observer.h
@@ -9,9 +9,11 @@
#include "cc/cc_export.h"
#include "cc/trees/render_frame_metadata.h"
-namespace cc {
+namespace viz {
+class CompositorFrameMetadata;
+}
-class FrameTokenAllocator;
+namespace cc {
// Observes RenderFrameMetadata associated with the submission of a frame.
// LayerTreeHostImpl will create the metadata when submitting a CompositorFrame.
@@ -24,12 +26,13 @@ class CC_EXPORT RenderFrameMetadataObserver {
// Binds on the current thread. This should only be called from the compositor
// thread.
- virtual void BindToCurrentThread(
- FrameTokenAllocator* frame_token_allocator) = 0;
+ virtual void BindToCurrentThread() = 0;
// Notification of the RendarFrameMetadata for the frame being submitted to
// the display compositor.
- virtual void OnRenderFrameSubmission(RenderFrameMetadata metadata) = 0;
+ virtual void OnRenderFrameSubmission(
+ const RenderFrameMetadata& render_frame_metadata,
+ viz::CompositorFrameMetadata* compositor_frame_metadata) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(RenderFrameMetadataObserver);
diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc
index 28c45b6196b..1d199d2f6d4 100644
--- a/chromium/cc/trees/single_thread_proxy.cc
+++ b/chromium/cc/trees/single_thread_proxy.cc
@@ -139,7 +139,7 @@ void SingleThreadProxy::SetLayerTreeFrameSink(
{
DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
DebugScopedSetImplThread impl(task_runner_provider_);
- success = host_impl_->InitializeRenderer(layer_tree_frame_sink);
+ success = host_impl_->InitializeFrameSink(layer_tree_frame_sink);
}
if (success) {
@@ -257,6 +257,10 @@ void SingleThreadProxy::SetNextCommitWaitsForActivation() {
DCHECK(task_runner_provider_->IsMainThread());
}
+bool SingleThreadProxy::RequestedAnimatePending() {
+ return animate_requested_ || commit_requested_;
+}
+
void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
DCHECK(task_runner_provider_->IsMainThread());
// Deferring commits only makes sense if there's a scheduler.
@@ -447,7 +451,8 @@ void SingleThreadProxy::DidReceiveCompositorFrameAckOnImplThread() {
}
void SingleThreadProxy::OnDrawForLayerTreeFrameSink(
- bool resourceless_software_draw) {
+ bool resourceless_software_draw,
+ bool skip_draw) {
NOTREACHED() << "Implemented by ThreadProxy for synchronous compositor.";
}
@@ -473,12 +478,11 @@ void SingleThreadProxy::NotifyImageDecodeRequestFinished() {
}
void SingleThreadProxy::DidPresentCompositorFrameOnImplThread(
- const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) {
- layer_tree_host_->DidPresentCompositorFrame(source_frames, time, refresh,
- flags);
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback) {
+ layer_tree_host_->DidPresentCompositorFrame(frame_token, std::move(callbacks),
+ feedback);
}
void SingleThreadProxy::RequestBeginMainFrameNotExpected(bool new_state) {
@@ -521,7 +525,13 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time,
#if DCHECK_IS_ON()
DCHECK(inside_impl_frame_);
#endif
+ animate_requested_ = false;
+ // Prevent new commits from being requested inside DoBeginMainFrame.
+ // Note: We do not want to prevent SetNeedsAnimate from requesting
+ // a commit here.
+ commit_requested_ = true;
DoBeginMainFrame(begin_frame_args);
+ commit_requested_ = false;
DoPainting();
DoCommit();
@@ -545,8 +555,7 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time,
if (raster) {
LayerTreeHostImpl::FrameData frame;
- frame.begin_frame_ack = viz::BeginFrameAck(
- begin_frame_args.source_id, begin_frame_args.sequence_number, true);
+ frame.begin_frame_ack = viz::BeginFrameAck(begin_frame_args, true);
DoComposite(&frame);
}
@@ -638,10 +647,10 @@ bool SingleThreadProxy::MainFrameWillHappenForTesting() {
return scheduler_on_impl_thread_->MainFrameForTestingWillHappen();
}
-void SingleThreadProxy::ClearHistoryOnNavigation() {
+void SingleThreadProxy::ClearHistory() {
DCHECK(task_runner_provider_->IsImplThread());
if (scheduler_on_impl_thread_)
- scheduler_on_impl_thread_->ClearHistoryOnNavigation();
+ scheduler_on_impl_thread_->ClearHistory();
}
void SingleThreadProxy::SetRenderFrameObserver(
@@ -744,7 +753,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, 0, begin_frame_args.frame_time,
+ ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT, begin_frame_args.frame_time,
1);
layer_tree_host_->QueueSwapPromise(
std::make_unique<LatencyInfoSwapPromise>(new_latency_info));
@@ -834,7 +843,8 @@ void SingleThreadProxy::ScheduledActionPrepareTiles() {
host_impl_->PrepareTiles();
}
-void SingleThreadProxy::ScheduledActionInvalidateLayerTreeFrameSink() {
+void SingleThreadProxy::ScheduledActionInvalidateLayerTreeFrameSink(
+ bool needs_redraw) {
// This is an Android WebView codepath, which only uses multi-thread
// compositor. So this should not occur in single-thread mode.
NOTREACHED() << "Android Webview use-case, so multi-thread only";
diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h
index f505320da40..0ff0f79de6e 100644
--- a/chromium/cc/trees/single_thread_proxy.h
+++ b/chromium/cc/trees/single_thread_proxy.h
@@ -49,10 +49,10 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
void SetNeedsCommit() override;
void SetNeedsRedraw(const gfx::Rect& damage_rect) override;
void SetNextCommitWaitsForActivation() override;
+ bool RequestedAnimatePending() override;
void NotifyInputThrottledUntilCommit() override {}
void SetDeferCommits(bool defer_commits) override;
bool CommitRequested() const override;
- void MainThreadHasStoppedFlinging() override {}
void Start() override;
void Stop() override;
void SetMutator(std::unique_ptr<LayerTreeMutator> mutator) override;
@@ -63,7 +63,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
// layout tests. This will still get called in the latter case, but we don't
// need to record UKM in that case.
}
- void ClearHistoryOnNavigation() override;
+ void ClearHistory() override;
void SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) override;
@@ -85,7 +85,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
void ScheduledActionActivateSyncTree() override;
void ScheduledActionBeginLayerTreeFrameSinkCreation() override;
void ScheduledActionPrepareTiles() override;
- void ScheduledActionInvalidateLayerTreeFrameSink() override;
+ void ScheduledActionInvalidateLayerTreeFrameSink(bool needs_redraw) override;
void ScheduledActionPerformImplSideInvalidation() override;
void SendBeginMainFrameNotExpectedSoon() override;
void ScheduledActionBeginMainFrameNotExpectedUntil(
@@ -117,15 +117,15 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
void WillPrepareTiles() override;
void DidPrepareTiles() override;
void DidCompletePageScaleAnimationOnImplThread() override;
- void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw) override;
+ void OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,
+ bool skip_draw) override;
void NeedsImplSideInvalidation(bool needs_first_draw_on_activation) override;
void RequestBeginMainFrameNotExpected(bool new_state) override;
void NotifyImageDecodeRequestFinished() override;
void DidPresentCompositorFrameOnImplThread(
- const std::vector<int>& source_frames,
- base::TimeTicks time,
- base::TimeDelta refresh,
- uint32_t flags) override;
+ uint32_t frame_token,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ const gfx::PresentationFeedback& feedback) override;
void RequestNewLayerTreeFrameSink();
diff --git a/chromium/cc/trees/swap_promise.h b/chromium/cc/trees/swap_promise.h
index c56b07155b3..b8663a61aa5 100644
--- a/chromium/cc/trees/swap_promise.h
+++ b/chromium/cc/trees/swap_promise.h
@@ -12,8 +12,6 @@
namespace cc {
-class FrameTokenAllocator;
-
// When a change to the compositor's state/invalidation/whatever happens, a
// Swap Promise can be inserted into LayerTreeHost/LayerTreeImpl, to track
// whether the compositor's reply to the new state/invaliadtion/whatever is
@@ -42,9 +40,9 @@ class FrameTokenAllocator;
// that the promise can be broken at either main or impl thread, e.g. commit
// fails on main thread, new frame data has no actual damage so
// LayerTreeHostImpl::SwapBuffers() bails out early on impl thread, so don't
-// assume that Did*() methods are called at a particular thread. It is better
-// to let the subclass carry thread-safe member data and operate on that
-// member data in Did*().
+// assume that DidNotSwap() method is called at a particular thread. It is
+// better to let the subclass carry thread-safe member data and operate on that
+// member data in DidNotSwap().
class CC_EXPORT SwapPromise {
public:
enum DidNotSwapReason {
@@ -54,21 +52,13 @@ class CC_EXPORT SwapPromise {
ACTIVATION_FAILS,
};
- enum class DidNotSwapAction {
- BREAK_PROMISE,
- KEEP_ACTIVE,
- };
-
SwapPromise() {}
virtual ~SwapPromise() {}
virtual void DidActivate() = 0;
- virtual void WillSwap(viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator) = 0;
+ virtual void WillSwap(viz::CompositorFrameMetadata* metadata) = 0;
virtual void DidSwap() = 0;
- // Return |KEEP_ACTIVE| if this promise should remain active (should not be
- // broken by the owner).
- virtual DidNotSwapAction DidNotSwap(DidNotSwapReason reason) = 0;
+ virtual void DidNotSwap(DidNotSwapReason reason) = 0;
// This is called when the main thread starts a (blocking) commit
virtual void OnCommit() {}
diff --git a/chromium/cc/trees/swap_promise_manager_unittest.cc b/chromium/cc/trees/swap_promise_manager_unittest.cc
index 3acf5aa1f4d..d88818e90e2 100644
--- a/chromium/cc/trees/swap_promise_manager_unittest.cc
+++ b/chromium/cc/trees/swap_promise_manager_unittest.cc
@@ -30,12 +30,9 @@ class MockSwapPromise : public SwapPromise {
~MockSwapPromise() override = default;
void DidActivate() override {}
- void WillSwap(viz::CompositorFrameMetadata* metadata,
- FrameTokenAllocator* frame_token_allocator) override {}
+ void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
void DidSwap() override {}
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
- return DidNotSwapAction::BREAK_PROMISE;
- }
+ void DidNotSwap(DidNotSwapReason reason) override {}
MOCK_METHOD0(OnCommit, void());
int64_t TraceId() const override { return 0; }
};
diff --git a/chromium/cc/trees/tree_synchronizer_unittest.cc b/chromium/cc/trees/tree_synchronizer_unittest.cc
index 98f3b049e4b..46e83a1b3b7 100644
--- a/chromium/cc/trees/tree_synchronizer_unittest.cc
+++ b/chromium/cc/trees/tree_synchronizer_unittest.cc
@@ -17,7 +17,9 @@
#include "cc/animation/animation_host.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
+#include "cc/layers/picture_layer.h"
#include "cc/test/animation_test_common.h"
+#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_impl_task_runner_provider.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_rendering_stats_instrumentation.h"
@@ -451,7 +453,8 @@ TEST_F(TreeSynchronizerTest, SyncMaskLayer) {
layer_tree_root->AddChild(Layer::Create());
// First child gets a mask layer.
- scoped_refptr<Layer> mask_layer = Layer::Create();
+ FakeContentLayerClient client;
+ scoped_refptr<PictureLayer> mask_layer = PictureLayer::Create(&client);
layer_tree_root->children()[0]->SetMaskLayer(mask_layer.get());
host_->SetRootLayer(layer_tree_root);
@@ -571,7 +574,7 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollTreeScrollOffsetMap) {
// the pending base and active base must be the same at this stage.
scoped_refptr<SyncedScrollOffset> scroll_layer_offset =
new SyncedScrollOffset;
- scroll_layer_offset->PushMainToPending(scroll_layer->scroll_offset());
+ scroll_layer_offset->PushMainToPending(scroll_layer->CurrentScrollOffset());
scroll_layer_offset->PushPendingToActive();
EXPECT_TRUE(AreScrollOffsetsEqual(
scroll_layer_offset.get(),
@@ -582,7 +585,7 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollTreeScrollOffsetMap) {
scoped_refptr<SyncedScrollOffset> transient_scroll_layer_offset =
new SyncedScrollOffset;
transient_scroll_layer_offset->PushMainToPending(
- transient_scroll_layer->scroll_offset());
+ transient_scroll_layer->CurrentScrollOffset());
transient_scroll_layer_offset->PushPendingToActive();
EXPECT_TRUE(
AreScrollOffsetsEqual(transient_scroll_layer_offset.get(),
@@ -604,7 +607,7 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollTreeScrollOffsetMap) {
scroll_tree.CollectScrollDeltas(scroll_info.get(), ElementId());
host_->proxy()->SetNeedsCommit();
host_->ApplyScrollAndScale(scroll_info.get());
- EXPECT_EQ(gfx::ScrollOffset(20, 30), scroll_layer->scroll_offset());
+ EXPECT_EQ(gfx::ScrollOffset(20, 30), scroll_layer->CurrentScrollOffset());
scroll_layer->SetScrollOffset(gfx::ScrollOffset(100, 100));
// More update to ScrollOffset active delta: gfx::ScrollOffset(20, 20)