summaryrefslogtreecommitdiffstats
path: root/chromium/cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:20:33 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:28:57 +0000
commitd17ea114e5ef69ad5d5d7413280a13e6428098aa (patch)
tree2c01a75df69f30d27b1432467cfe7c1467a498da /chromium/cc
parent8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (diff)
BASELINE: Update Chromium to 67.0.3396.47
Change-Id: Idcb1341782e417561a2473eeecc82642dafda5b7 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn18
-rw-r--r--chromium/cc/PRESUBMIT.py2
-rw-r--r--chromium/cc/animation/README.md2
-rw-r--r--chromium/cc/animation/animation_host.cc3
-rw-r--r--chromium/cc/animation/animation_host.h1
-rw-r--r--chromium/cc/animation/animation_unittest.cc (renamed from chromium/cc/animation/animation_player_unittest.cc)0
-rw-r--r--chromium/cc/animation/element_animations.cc1
-rw-r--r--chromium/cc/animation/keyframe_model_unittest.cc1
-rw-r--r--chromium/cc/animation/keyframed_animation_curve_unittest.cc97
-rw-r--r--chromium/cc/animation/scroll_offset_animations_impl.h1
-rw-r--r--chromium/cc/animation/transform_operations.cc6
-rw-r--r--chromium/cc/animation/transform_operations.h3
-rw-r--r--chromium/cc/animation/transform_operations_unittest.cc27
-rw-r--r--chromium/cc/animation/worklet_animation.cc1
-rw-r--r--chromium/cc/animation/worklet_animation_player_unittest.cc135
-rw-r--r--chromium/cc/animation/worklet_animation_unittest.cc1
-rw-r--r--chromium/cc/base/math_util.cc16
-rw-r--r--chromium/cc/base/math_util.h7
-rw-r--r--chromium/cc/base/rtree.h26
-rw-r--r--chromium/cc/base/rtree_unittest.cc5
-rw-r--r--chromium/cc/benchmarks/invalidation_benchmark.cc1
-rw-r--r--chromium/cc/benchmarks/micro_benchmark_controller.cc1
-rw-r--r--chromium/cc/benchmarks/rasterize_and_record_benchmark.cc29
-rw-r--r--chromium/cc/benchmarks/rasterize_and_record_benchmark.h6
-rw-r--r--chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc10
-rw-r--r--chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.h1
-rw-r--r--chromium/cc/blink/BUILD.gn4
-rw-r--r--chromium/cc/blink/DEPS2
-rw-r--r--chromium/cc/blink/scrollbar_impl.cc13
-rw-r--r--chromium/cc/blink/scrollbar_impl.h3
-rw-r--r--chromium/cc/blink/web_blend_mode.h2
-rw-r--r--chromium/cc/blink/web_compositor_support_impl.cc1
-rw-r--r--chromium/cc/blink/web_compositor_support_impl.h6
-rw-r--r--chromium/cc/blink/web_content_layer_impl.cc11
-rw-r--r--chromium/cc/blink/web_content_layer_impl.h2
-rw-r--r--chromium/cc/blink/web_display_item_list_impl.cc6
-rw-r--r--chromium/cc/blink/web_display_item_list_impl.h4
-rw-r--r--chromium/cc/blink/web_display_item_list_impl_unittest.cc2
-rw-r--r--chromium/cc/blink/web_external_texture_layer_impl.cc8
-rw-r--r--chromium/cc/blink/web_external_texture_layer_impl.h4
-rw-r--r--chromium/cc/blink/web_image_layer_impl.h2
-rw-r--r--chromium/cc/blink/web_layer_impl.cc16
-rw-r--r--chromium/cc/blink/web_layer_impl.h22
-rw-r--r--chromium/cc/blink/web_layer_impl_fixed_bounds.cc4
-rw-r--r--chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc6
-rw-r--r--chromium/cc/blink/web_scrollbar_layer_impl.cc1
-rw-r--r--chromium/cc/blink/web_scrollbar_layer_impl.h4
-rw-r--r--chromium/cc/input/browser_controls_offset_manager_unittest.cc1
-rw-r--r--chromium/cc/input/input_handler.h13
-rw-r--r--chromium/cc/input/scroll_snap_data.cc177
-rw-r--r--chromium/cc/input/scroll_snap_data.h55
-rw-r--r--chromium/cc/input/scroll_snap_data_unittest.cc101
-rw-r--r--chromium/cc/input/scrollbar.h3
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.cc39
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.h8
-rw-r--r--chromium/cc/input/scrollbar_animation_controller_unittest.cc48
-rw-r--r--chromium/cc/ipc/cc_param_traits.cc12
-rw-r--r--chromium/cc/ipc/cc_param_traits_macros.h1
-rw-r--r--chromium/cc/ipc/cc_param_traits_unittest.cc8
-rw-r--r--chromium/cc/ipc/cc_serialization_perftest.cc11
-rw-r--r--chromium/cc/layers/deadline_policy.cc17
-rw-r--r--chromium/cc/layers/deadline_policy.h14
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc48
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.h2
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl_unittest.cc18
-rw-r--r--chromium/cc/layers/layer.cc26
-rw-r--r--chromium/cc/layers/layer.h8
-rw-r--r--chromium/cc/layers/layer_client.h2
-rw-r--r--chromium/cc/layers/layer_impl.cc13
-rw-r--r--chromium/cc/layers/layer_impl.h12
-rw-r--r--chromium/cc/layers/layer_impl_test_properties.h1
-rw-r--r--chromium/cc/layers/layer_unittest.cc16
-rw-r--r--chromium/cc/layers/nine_patch_generator.h1
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer.cc51
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer.h2
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc56
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h15
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc88
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc31
-rw-r--r--chromium/cc/layers/picture_layer_impl.h1
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc1
-rw-r--r--chromium/cc/layers/picture_layer_unittest.cc1
-rw-r--r--chromium/cc/layers/recording_source.cc4
-rw-r--r--chromium/cc/layers/recording_source_unittest.cc1
-rw-r--r--chromium/cc/layers/render_surface_unittest.cc2
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.cc4
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.h4
-rw-r--r--chromium/cc/layers/scrollbar_layer_unittest.cc1
-rw-r--r--chromium/cc/layers/surface_layer.cc9
-rw-r--r--chromium/cc/layers/surface_layer.h7
-rw-r--r--chromium/cc/layers/surface_layer_impl.cc13
-rw-r--r--chromium/cc/layers/surface_layer_impl.h5
-rw-r--r--chromium/cc/layers/surface_layer_unittest.cc12
-rw-r--r--chromium/cc/layers/texture_layer.cc59
-rw-r--r--chromium/cc/layers/texture_layer.h46
-rw-r--r--chromium/cc/layers/texture_layer_client.h2
-rw-r--r--chromium/cc/layers/texture_layer_impl.cc109
-rw-r--r--chromium/cc/layers/texture_layer_impl.h36
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc564
-rw-r--r--chromium/cc/layers/touch_action_region.cc1
-rw-r--r--chromium/cc/layers/ui_resource_layer.cc1
-rw-r--r--chromium/cc/layers/video_layer_impl.cc7
-rw-r--r--chromium/cc/paint/BUILD.gn15
-rw-r--r--chromium/cc/paint/DEPS3
-rw-r--r--chromium/cc/paint/color_space_transfer_cache_entry.cc4
-rw-r--r--chromium/cc/paint/color_space_transfer_cache_entry.h2
-rw-r--r--chromium/cc/paint/decode_stashing_image_provider.cc4
-rw-r--r--chromium/cc/paint/discardable_image_map.cc109
-rw-r--r--chromium/cc/paint/discardable_image_map_unittest.cc81
-rw-r--r--chromium/cc/paint/display_item_list.cc35
-rw-r--r--chromium/cc/paint/display_item_list.h77
-rw-r--r--chromium/cc/paint/display_item_list_unittest.cc130
-rw-r--r--chromium/cc/paint/image_analysis_state.h18
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.cc65
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.h3
-rw-r--r--chromium/cc/paint/oop_pixeltest.cc382
-rw-r--r--chromium/cc/paint/paint_filter.cc286
-rw-r--r--chromium/cc/paint/paint_filter.h134
-rw-r--r--chromium/cc/paint/paint_filter_unittest.cc197
-rw-r--r--chromium/cc/paint/paint_flags.cc25
-rw-r--r--chromium/cc/paint/paint_image.h1
-rw-r--r--chromium/cc/paint/paint_image_builder.h1
-rw-r--r--chromium/cc/paint/paint_op_buffer.cc20
-rw-r--r--chromium/cc/paint/paint_op_buffer.h40
-rw-r--r--chromium/cc/paint/paint_op_buffer_unittest.cc28
-rw-r--r--chromium/cc/paint/paint_op_perftest.cc7
-rw-r--r--chromium/cc/paint/paint_op_reader.cc93
-rw-r--r--chromium/cc/paint/paint_op_reader.h1
-rw-r--r--chromium/cc/paint/paint_op_writer.cc78
-rw-r--r--chromium/cc/paint/paint_op_writer.h1
-rw-r--r--chromium/cc/paint/paint_record.cc13
-rw-r--r--chromium/cc/paint/paint_record.h10
-rw-r--r--chromium/cc/paint/paint_recorder.h1
-rw-r--r--chromium/cc/paint/paint_shader.cc20
-rw-r--r--chromium/cc/paint/paint_shader.h18
-rw-r--r--chromium/cc/paint/paint_shader_unittest.cc2
-rw-r--r--chromium/cc/paint/paint_text_blob.h2
-rw-r--r--chromium/cc/paint/paint_typeface_transfer_cache_entry.cc6
-rw-r--r--chromium/cc/paint/paint_typeface_transfer_cache_entry.h6
-rw-r--r--chromium/cc/paint/raw_memory_transfer_cache_entry.cc5
-rw-r--r--chromium/cc/paint/raw_memory_transfer_cache_entry.h2
-rw-r--r--chromium/cc/paint/record_paint_canvas.cc1
-rw-r--r--chromium/cc/paint/scoped_raster_flags.cc41
-rw-r--r--chromium/cc/paint/scoped_raster_flags.h2
-rw-r--r--chromium/cc/paint/scoped_raster_flags_unittest.cc2
-rw-r--r--chromium/cc/paint/skia_paint_canvas.cc1
-rw-r--r--chromium/cc/paint/transfer_cache_entry.cc1
-rw-r--r--chromium/cc/paint/transfer_cache_entry.h3
-rw-r--r--chromium/cc/paint/transfer_cache_fuzzer.cc41
-rw-r--r--chromium/cc/raster/bitmap_raster_buffer_provider.cc58
-rw-r--r--chromium/cc/raster/bitmap_raster_buffer_provider.h13
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.cc171
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.h10
-rw-r--r--chromium/cc/raster/one_copy_raster_buffer_provider.cc76
-rw-r--r--chromium/cc/raster/one_copy_raster_buffer_provider.h2
-rw-r--r--chromium/cc/raster/playback_image_provider.cc8
-rw-r--r--chromium/cc/raster/playback_image_provider.h6
-rw-r--r--chromium/cc/raster/playback_image_provider_unittest.cc15
-rw-r--r--chromium/cc/raster/raster_buffer_provider.h3
-rw-r--r--chromium/cc/raster/raster_buffer_provider_perftest.cc17
-rw-r--r--chromium/cc/raster/raster_buffer_provider_unittest.cc61
-rw-r--r--chromium/cc/raster/raster_source.cc3
-rw-r--r--chromium/cc/raster/scoped_gpu_raster.cc8
-rw-r--r--chromium/cc/raster/staging_buffer_pool.cc15
-rw-r--r--chromium/cc/raster/zero_copy_raster_buffer_provider.cc5
-rw-r--r--chromium/cc/raster/zero_copy_raster_buffer_provider.h1
-rw-r--r--chromium/cc/resources/cross_thread_shared_bitmap.cc18
-rw-r--r--chromium/cc/resources/cross_thread_shared_bitmap.h51
-rw-r--r--chromium/cc/resources/display_resource_provider.cc153
-rw-r--r--chromium/cc/resources/display_resource_provider.h40
-rw-r--r--chromium/cc/resources/display_resource_provider_unittest.cc548
-rw-r--r--chromium/cc/resources/layer_tree_resource_provider.cc55
-rw-r--r--chromium/cc/resources/layer_tree_resource_provider.h7
-rw-r--r--chromium/cc/resources/layer_tree_resource_provider_unittest.cc4
-rw-r--r--chromium/cc/resources/resource_pool.cc50
-rw-r--r--chromium/cc/resources/resource_pool.h53
-rw-r--r--chromium/cc/resources/resource_pool_unittest.cc4
-rw-r--r--chromium/cc/resources/resource_provider.cc75
-rw-r--r--chromium/cc/resources/resource_provider.h5
-rw-r--r--chromium/cc/resources/resource_provider_unittest.cc85
-rw-r--r--chromium/cc/resources/resource_util.h218
-rw-r--r--chromium/cc/resources/resource_util_unittest.cc30
-rw-r--r--chromium/cc/resources/shared_bitmap_id_registrar.cc35
-rw-r--r--chromium/cc/resources/shared_bitmap_id_registrar.h72
-rw-r--r--chromium/cc/resources/video_resource_updater.cc1250
-rw-r--r--chromium/cc/resources/video_resource_updater.h209
-rw-r--r--chromium/cc/resources/video_resource_updater_unittest.cc318
-rw-r--r--chromium/cc/scheduler/scheduler.cc1
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.cc5
-rw-r--r--chromium/cc/scheduler/scheduler_unittest.cc43
-rw-r--r--chromium/cc/tiles/checker_image_tracker.cc1
-rw-r--r--chromium/cc/tiles/checker_image_tracker_unittest.cc1
-rw-r--r--chromium/cc/tiles/eviction_tile_priority_queue.cc1
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.cc43
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.h7
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_unittest.cc104
-rw-r--r--chromium/cc/tiles/picture_layer_tiling.cc1
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set_unittest.cc1
-rw-r--r--chromium/cc/tiles/raster_tile_priority_queue_all.cc1
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.cc30
-rw-r--r--chromium/cc/tiles/tile.cc4
-rw-r--r--chromium/cc/tiles/tile_draw_info.cc5
-rw-r--r--chromium/cc/tiles/tile_draw_info.h5
-rw-r--r--chromium/cc/tiles/tile_manager.cc124
-rw-r--r--chromium/cc/tiles/tile_manager.h26
-rw-r--r--chromium/cc/tiles/tile_manager_perftest.cc1
-rw-r--r--chromium/cc/tiles/tile_manager_settings.h1
-rw-r--r--chromium/cc/tiles/tile_manager_unittest.cc96
-rw-r--r--chromium/cc/trees/clip_node.cc1
-rw-r--r--chromium/cc/trees/draw_property_utils.cc5
-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/image_animation_controller.cc35
-rw-r--r--chromium/cc/trees/image_animation_controller.h21
-rw-r--r--chromium/cc/trees/image_animation_controller_unittest.cc155
-rw-r--r--chromium/cc/trees/latency_info_swap_promise.cc4
-rw-r--r--chromium/cc/trees/latency_info_swap_promise.h3
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink.h5
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink_unittest.cc1
-rw-r--r--chromium/cc/trees/layer_tree_host.cc41
-rw-r--r--chromium/cc/trees/layer_tree_host.h8
-rw-r--r--chromium/cc/trees/layer_tree_host_common_unittest.cc47
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc503
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h129
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc340
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc4
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc37
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc31
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_animation.cc191
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_context.cc1
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc31
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_scroll.cc1
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc48
-rw-r--r--chromium/cc/trees/layer_tree_impl.h11
-rw-r--r--chromium/cc/trees/layer_tree_impl_unittest.cc12
-rw-r--r--chromium/cc/trees/layer_tree_settings.cc1
-rw-r--r--chromium/cc/trees/layer_tree_settings.h10
-rw-r--r--chromium/cc/trees/mutator_host.h1
-rw-r--r--chromium/cc/trees/property_tree_builder.cc1
-rw-r--r--chromium/cc/trees/proxy_impl.cc1
-rw-r--r--chromium/cc/trees/proxy_main.cc1
-rw-r--r--chromium/cc/trees/render_frame_metadata.cc14
-rw-r--r--chromium/cc/trees/render_frame_metadata.h29
-rw-r--r--chromium/cc/trees/render_frame_metadata_observer.h7
-rw-r--r--chromium/cc/trees/swap_promise.h5
-rw-r--r--chromium/cc/trees/swap_promise_manager_unittest.cc4
246 files changed, 7865 insertions, 2534 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
index 30d71bb6528..19828e3374a 100644
--- a/chromium/cc/BUILD.gn
+++ b/chromium/cc/BUILD.gn
@@ -175,6 +175,8 @@ cc_component("cc") {
"raster/tile_task.h",
"raster/zero_copy_raster_buffer_provider.cc",
"raster/zero_copy_raster_buffer_provider.h",
+ "resources/cross_thread_shared_bitmap.cc",
+ "resources/cross_thread_shared_bitmap.h",
"resources/display_resource_provider.cc",
"resources/display_resource_provider.h",
"resources/layer_tree_resource_provider.cc",
@@ -186,9 +188,10 @@ cc_component("cc") {
"resources/resource_pool.h",
"resources/resource_provider.cc",
"resources/resource_provider.h",
- "resources/resource_util.h",
"resources/scoped_ui_resource.cc",
"resources/scoped_ui_resource.h",
+ "resources/shared_bitmap_id_registrar.cc",
+ "resources/shared_bitmap_id_registrar.h",
"resources/ui_resource_bitmap.cc",
"resources/ui_resource_bitmap.h",
"resources/ui_resource_client.h",
@@ -277,6 +280,8 @@ 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",
@@ -372,7 +377,7 @@ cc_component("cc") {
"//gpu/command_buffer/client:raster_interface",
"//gpu/ipc:gl_in_process_context",
"//gpu/skia_bindings:skia_bindings",
- "//gpu/vulkan:features",
+ "//gpu/vulkan:buildflags",
"//media",
"//mojo/public/cpp/bindings:struct_traits",
"//services/metrics/public/cpp:ukm_builders",
@@ -589,6 +594,7 @@ cc_test("cc_unittests") {
"layers/nine_patch_generator_unittest.cc",
"layers/nine_patch_layer_impl_unittest.cc",
"layers/nine_patch_layer_unittest.cc",
+ "layers/painted_overlay_scrollbar_layer_unittest.cc",
"layers/painted_scrollbar_layer_impl_unittest.cc",
"layers/painted_scrollbar_layer_unittest.cc",
"layers/picture_image_layer_unittest.cc",
@@ -614,6 +620,7 @@ cc_test("cc_unittests") {
"paint/display_item_list_unittest.cc",
"paint/filter_operations_unittest.cc",
"paint/oop_pixeltest.cc",
+ "paint/paint_filter_unittest.cc",
"paint/paint_image_unittest.cc",
"paint/paint_op_buffer_unittest.cc",
"paint/paint_op_helper_unittest.cc",
@@ -631,6 +638,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/display_resource_provider_unittest.cc",
"resources/layer_tree_resource_provider_unittest.cc",
"resources/resource_pool_unittest.cc",
"resources/resource_provider_unittest.cc",
@@ -685,8 +693,8 @@ cc_test("cc_unittests") {
# Animation test files.
"animation/animation_host_unittest.cc",
- "animation/animation_player_unittest.cc",
"animation/animation_timeline_unittest.cc",
+ "animation/animation_unittest.cc",
"animation/element_animations_unittest.cc",
"animation/keyframe_model_unittest.cc",
"animation/keyframed_animation_curve_unittest.cc",
@@ -736,7 +744,7 @@ cc_test("cc_unittests") {
"//gpu/ipc:gl_in_process_context",
"//gpu/skia_bindings",
"//media",
- "//mojo/edk/system",
+ "//mojo/edk",
"//mojo/public/cpp/bindings",
"//testing/gmock",
"//testing/gtest",
@@ -788,7 +796,7 @@ cc_test("cc_perftests") {
"//gpu/command_buffer/client:raster",
"//gpu/ipc/common:struct_traits",
"//media",
- "//mojo/edk/system",
+ "//mojo/edk",
"//mojo/public/cpp/bindings",
"//services/viz/public/interfaces",
"//skia",
diff --git a/chromium/cc/PRESUBMIT.py b/chromium/cc/PRESUBMIT.py
index 26909c0b294..3ddbde82ec0 100644
--- a/chromium/cc/PRESUBMIT.py
+++ b/chromium/cc/PRESUBMIT.py
@@ -318,6 +318,6 @@ def PostUploadHook(cl, change, output_api):
cl,
[
'master.tryserver.blink:linux_trusty_blink_rel',
- 'master.tryserver.chromium.android:android_optional_gpu_tests_rel',
+ 'luci.chromium.try:android_optional_gpu_tests_rel',
],
'Automatically added Blink and Android GPU trybots for CQ.')
diff --git a/chromium/cc/animation/README.md b/chromium/cc/animation/README.md
index 7f68611486b..12359aad369 100644
--- a/chromium/cc/animation/README.md
+++ b/chromium/cc/animation/README.md
@@ -157,5 +157,5 @@ base. [Smooth Scrolling in Chromium](https://goo.gl/XXwAwk) provides
an overview of smooth scrolling. There is further class header
documentation in
Blink's
-[platform/scroll](https://codesearch.chromium.org/chromium/src/third_party/WebKit/Source/platform/scroll/)
+[platform/scroll](https://codesearch.chromium.org/chromium/src/third_party/blink/renderer/platform/scroll/)
directory.
diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc
index f6efdcceaec..0b17d50a78e 100644
--- a/chromium/cc/animation/animation_host.cc
+++ b/chromium/cc/animation/animation_host.cc
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/animation/animation.h"
@@ -659,7 +660,7 @@ void AnimationHost::SetAnimationCounts(
// If an animation is being run on the compositor, it will have a ticking
// Animation (which will have a corresponding impl-thread version). Therefore
// to find the count of main-only animations, we can simply subtract the
- // number of ticking players from the total count.
+ // number of ticking animations from the total count.
size_t ticking_animations_count = ticking_animations_.size();
if (main_thread_animations_count_ !=
total_animations_count - ticking_animations_count) {
diff --git a/chromium/cc/animation/animation_host.h b/chromium/cc/animation/animation_host.h
index 23f5500a06a..6a639b15e60 100644
--- a/chromium/cc/animation/animation_host.h
+++ b/chromium/cc/animation/animation_host.h
@@ -10,7 +10,6 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
diff --git a/chromium/cc/animation/animation_player_unittest.cc b/chromium/cc/animation/animation_unittest.cc
index 6bef965ac93..6bef965ac93 100644
--- a/chromium/cc/animation/animation_player_unittest.cc
+++ b/chromium/cc/animation/animation_unittest.cc
diff --git a/chromium/cc/animation/element_animations.cc b/chromium/cc/animation/element_animations.cc
index ddb9625f83a..cea0c141feb 100644
--- a/chromium/cc/animation/element_animations.cc
+++ b/chromium/cc/animation/element_animations.cc
@@ -9,7 +9,6 @@
#include <algorithm>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/numerics/ranges.h"
#include "cc/animation/animation_delegate.h"
#include "cc/animation/animation_events.h"
diff --git a/chromium/cc/animation/keyframe_model_unittest.cc b/chromium/cc/animation/keyframe_model_unittest.cc
index df583614674..ac13921648b 100644
--- a/chromium/cc/animation/keyframe_model_unittest.cc
+++ b/chromium/cc/animation/keyframe_model_unittest.cc
@@ -4,7 +4,6 @@
#include "cc/animation/keyframe_model.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "cc/test/animation_test_common.h"
#include "cc/trees/target_property.h"
diff --git a/chromium/cc/animation/keyframed_animation_curve_unittest.cc b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
index f714b28341f..7a13c743e4e 100644
--- a/chromium/cc/animation/keyframed_animation_curve_unittest.cc
+++ b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
@@ -5,6 +5,7 @@
#include "cc/animation/keyframed_animation_curve.h"
#include "cc/animation/transform_operations.h"
+#include "cc/test/geometry_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/animation/tween.h"
@@ -304,6 +305,102 @@ TEST(KeyframedAnimationCurveTest, RepeatedTransformKeyTimes) {
ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
+// Tests that a discrete transform animation (e.g. where one or more keyframes
+// is a non-invertible matrix) works as expected.
+TEST(KeyframedAnimationCurveTest, DiscreteLinearTransformAnimation) {
+ gfx::Transform non_invertible_matrix(0, 0, 0, 0, 0, 0);
+ gfx::Transform identity_matrix;
+
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+ TransformOperations operations1;
+ operations1.AppendMatrix(non_invertible_matrix);
+ TransformOperations operations2;
+ operations2.AppendMatrix(identity_matrix);
+ TransformOperations operations3;
+ operations3.AppendMatrix(non_invertible_matrix);
+
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.0), operations3, nullptr));
+
+ TransformOperations result;
+
+ // Between 0 and 0.5 seconds, the first keyframe should be returned.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.01f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.49f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
+
+ // Between 0.5 and 1.5 seconds, the middle keyframe should be returned.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.5f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(1.49f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, result.Apply());
+
+ // Between 1.5 and 2.0 seconds, the last keyframe should be returned.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(1.5f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(2.0f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
+}
+
+TEST(KeyframedAnimationCurveTest, DiscreteCubicBezierTransformAnimation) {
+ gfx::Transform non_invertible_matrix(0, 0, 0, 0, 0, 0);
+ gfx::Transform identity_matrix;
+
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+ TransformOperations operations1;
+ operations1.AppendMatrix(non_invertible_matrix);
+ TransformOperations operations2;
+ operations2.AppendMatrix(identity_matrix);
+ TransformOperations operations3;
+ operations3.AppendMatrix(non_invertible_matrix);
+
+ // The cubic-bezier here is a nice fairly strong ease-in curve, where 50%
+ // progression is at approximately 85% of the time.
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta(), operations1,
+ CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2,
+ CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.0), operations3,
+ CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
+
+ TransformOperations result;
+
+ // Due to the cubic-bezier, the first keyframe is returned almost all the way
+ // to 1 second.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.01f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.8f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
+
+ // Between ~0.85 and ~1.85 seconds, the middle keyframe should be returned.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.85f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(1.8f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, result.Apply());
+
+ // Finally the last keyframe only takes effect after ~1.85 seconds.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(1.85f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(2.0f));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
+}
+
// Tests that a filter animation with one keyframe works as expected.
TEST(KeyframedAnimationCurveTest, OneFilterKeyframe) {
std::unique_ptr<KeyframedFilterAnimationCurve> curve(
diff --git a/chromium/cc/animation/scroll_offset_animations_impl.h b/chromium/cc/animation/scroll_offset_animations_impl.h
index 69341f89fc2..e64456eb9f0 100644
--- a/chromium/cc/animation/scroll_offset_animations_impl.h
+++ b/chromium/cc/animation/scroll_offset_animations_impl.h
@@ -6,7 +6,6 @@
#define CC_ANIMATION_SCROLL_OFFSET_ANIMATIONS_IMPL_H_
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "cc/animation/animation_delegate.h"
#include "cc/animation/scroll_offset_animation_curve.h"
diff --git a/chromium/cc/animation/transform_operations.cc b/chromium/cc/animation/transform_operations.cc
index 5e4e8070d25..9b456185030 100644
--- a/chromium/cc/animation/transform_operations.cc
+++ b/chromium/cc/animation/transform_operations.cc
@@ -53,7 +53,11 @@ gfx::Transform TransformOperations::Apply() const {
TransformOperations TransformOperations::Blend(const TransformOperations& from,
SkMScalar progress) const {
TransformOperations to_return;
- BlendInternal(from, progress, &to_return);
+ if (!BlendInternal(from, progress, &to_return)) {
+ // If the matrices cannot be blended, fallback to discrete animation logic.
+ // See https://drafts.csswg.org/css-transforms/#matrix-interpolation
+ to_return = progress < 0.5 ? from : *this;
+ }
return to_return;
}
diff --git a/chromium/cc/animation/transform_operations.h b/chromium/cc/animation/transform_operations.h
index b74ddacf65b..081da5932c9 100644
--- a/chromium/cc/animation/transform_operations.h
+++ b/chromium/cc/animation/transform_operations.h
@@ -48,6 +48,9 @@ class CC_ANIMATION_EXPORT TransformOperations {
// transforms are baked to matrices (using apply), and the matrices are
// then decomposed and interpolated. For more information, see
// http://www.w3.org/TR/2011/WD-css3-2d-transforms-20111215/#matrix-decomposition.
+ //
+ // If either of the matrices are non-decomposable for the blend, Blend applies
+ // discrete interpolation between them based on the progress value.
TransformOperations Blend(const TransformOperations& from,
SkMScalar progress) const;
diff --git a/chromium/cc/animation/transform_operations_unittest.cc b/chromium/cc/animation/transform_operations_unittest.cc
index ca73a5a417a..ac7e5289d9f 100644
--- a/chromium/cc/animation/transform_operations_unittest.cc
+++ b/chromium/cc/animation/transform_operations_unittest.cc
@@ -9,7 +9,6 @@
#include <limits>
#include <vector>
-#include "base/memory/ptr_util.h"
#include "cc/test/geometry_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/animation/tween.h"
@@ -857,6 +856,32 @@ TEST(TransformOperationTest, ExtrapolateMatrixBlending) {
operations1.Blend(operations2, -0.5).Apply());
}
+TEST(TransformOperationTest, NonDecomposableBlend) {
+ TransformOperations non_decomposible_transform;
+ gfx::Transform non_decomposible_matrix(0, 0, 0, 0, 0, 0);
+ non_decomposible_transform.AppendMatrix(non_decomposible_matrix);
+
+ TransformOperations identity_transform;
+ gfx::Transform identity_matrix;
+ identity_transform.AppendMatrix(identity_matrix);
+
+ // Before the half-way point, we should return the 'from' matrix.
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ non_decomposible_matrix,
+ identity_transform.Blend(non_decomposible_transform, 0.0f).Apply());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ non_decomposible_matrix,
+ identity_transform.Blend(non_decomposible_transform, 0.49f).Apply());
+
+ // After the half-way point, we should return the 'to' matrix.
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ identity_matrix,
+ identity_transform.Blend(non_decomposible_transform, 0.5f).Apply());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ identity_matrix,
+ identity_transform.Blend(non_decomposible_transform, 1.0f).Apply());
+}
+
TEST(TransformOperationTest, BlendedBoundsWhenTypesDoNotMatch) {
TransformOperations operations_from;
operations_from.AppendScale(2.0, 4.0, 8.0);
diff --git a/chromium/cc/animation/worklet_animation.cc b/chromium/cc/animation/worklet_animation.cc
index 8ad26c2ae6f..5db8231c413 100644
--- a/chromium/cc/animation/worklet_animation.cc
+++ b/chromium/cc/animation/worklet_animation.cc
@@ -4,7 +4,6 @@
#include "cc/animation/worklet_animation.h"
-#include "base/memory/ptr_util.h"
#include "cc/animation/scroll_timeline.h"
namespace cc {
diff --git a/chromium/cc/animation/worklet_animation_player_unittest.cc b/chromium/cc/animation/worklet_animation_player_unittest.cc
new file mode 100644
index 00000000000..d77e0a7bb5d
--- /dev/null
+++ b/chromium/cc/animation/worklet_animation_player_unittest.cc
@@ -0,0 +1,135 @@
+// 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/animation/worklet_animation_player.h"
+
+#include "cc/animation/scroll_timeline.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 "cc/trees/property_tree.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::_;
+
+namespace cc {
+
+namespace {
+
+class WorkletAnimationPlayerTest : public AnimationTimelinesTest {
+ public:
+ WorkletAnimationPlayerTest() = default;
+ ~WorkletAnimationPlayerTest() override = default;
+
+ int worklet_player_id_ = 11;
+};
+
+class MockScrollTimeline : public ScrollTimeline {
+ public:
+ MockScrollTimeline()
+ : ScrollTimeline(ElementId(), ScrollTimeline::Vertical, 0) {}
+ MOCK_CONST_METHOD1(CurrentTime, double(const ScrollTree&));
+};
+
+TEST_F(WorkletAnimationPlayerTest, LocalTimeIsUsedWithAnimations) {
+ client_.RegisterElement(element_id_, ElementListType::ACTIVE);
+ client_impl_.RegisterElement(element_id_, ElementListType::PENDING);
+ client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE);
+
+ 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;
+
+ scoped_refptr<WorkletAnimationPlayer> worklet_player_ =
+ WorkletAnimationPlayer::Create(worklet_player_id_, "test_name", nullptr);
+
+ worklet_player_->AttachElement(element_id_);
+ host_->AddAnimationTimeline(timeline_);
+ timeline_->AttachPlayer(worklet_player_);
+
+ AddOpacityTransitionToPlayer(worklet_player_.get(), duration, start_opacity,
+ end_opacity, true);
+
+ host_->PushPropertiesTo(host_impl_);
+ host_impl_->ActivateAnimations();
+
+ // TODO(majidvp): At the moment the player does not use the local time when
+ // it is starting. This is because KeyframeModel::ConvertToActiveTime always
+ // returns the time_offset when starting. We need to change this.
+ base::TimeTicks time;
+ time += base::TimeDelta::FromSecondsD(0.1);
+ TickAnimationsTransferEvents(time, 1u);
+
+ base::TimeDelta local_time = base::TimeDelta::FromSecondsD(duration / 2);
+ worklet_player_->SetLocalTime(local_time);
+
+ host_->PushPropertiesTo(host_impl_);
+
+ TickAnimationsTransferEvents(time, 0u);
+
+ client_.ExpectOpacityPropertyMutated(element_id_, ElementListType::ACTIVE,
+ expected_opacity);
+
+ 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(WorkletAnimationPlayerTest,
+ LayerTreeMutatorsIsMutatedWithCorrectInputState) {
+ MockLayerTreeMutator* mock_mutator = new MockLayerTreeMutator();
+ host_impl_->SetLayerTreeMutator(
+ base::WrapUnique<LayerTreeMutator>(mock_mutator));
+
+ client_.RegisterElement(element_id_, ElementListType::ACTIVE);
+ client_impl_.RegisterElement(element_id_, ElementListType::PENDING);
+ client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE);
+
+ const float start_opacity = .7f;
+ const float end_opacity = .3f;
+ const double duration = 1.;
+
+ scoped_refptr<WorkletAnimationPlayer> worklet_player_ =
+ WorkletAnimationPlayer::Create(worklet_player_id_, "test_name", nullptr);
+
+ worklet_player_->AttachElement(element_id_);
+ host_->AddAnimationTimeline(timeline_);
+ timeline_->AttachPlayer(worklet_player_);
+
+ AddOpacityTransitionToPlayer(worklet_player_.get(), duration, start_opacity,
+ end_opacity, true);
+
+ host_->PushPropertiesTo(host_impl_);
+ host_impl_->ActivateAnimations();
+
+ EXPECT_CALL(*mock_mutator, MutateRef(_));
+
+ base::TimeTicks time;
+ time += base::TimeDelta::FromSecondsD(0.1);
+ TickAnimationsTransferEvents(time, 1u);
+
+ Mock::VerifyAndClearExpectations(mock_mutator);
+}
+
+TEST_F(WorkletAnimationPlayerTest, CurrentTimeCorrectlyUsesScrolltimeline) {
+ auto scroll_timeline = std::make_unique<MockScrollTimeline>();
+ EXPECT_CALL(*scroll_timeline, CurrentTime(_)).WillOnce(Return(1234));
+ scoped_refptr<WorkletAnimationPlayer> worklet_player =
+ WorkletAnimationPlayer::Create(worklet_player_id_, "test_name",
+ std::move(scroll_timeline));
+
+ ScrollTree scroll_tree;
+ EXPECT_EQ(1234,
+ worklet_player->CurrentTime(base::TimeTicks::Now(), scroll_tree));
+}
+
+} // namespace
+
+} // namespace cc
diff --git a/chromium/cc/animation/worklet_animation_unittest.cc b/chromium/cc/animation/worklet_animation_unittest.cc
index 36e65fc0f01..ef89d6fb11f 100644
--- a/chromium/cc/animation/worklet_animation_unittest.cc
+++ b/chromium/cc/animation/worklet_animation_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/animation/worklet_animation.h"
+#include "base/memory/ptr_util.h"
#include "cc/animation/scroll_timeline.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/animation_timelines_test_common.h"
diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc
index ede2ef124ed..7ac7fb42f5e 100644
--- a/chromium/cc/base/math_util.cc
+++ b/chromium/cc/base/math_util.cc
@@ -270,6 +270,22 @@ gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
return ComputeEnclosingClippedRect(h1, h2, h3, h4);
}
+gfx::QuadF MathUtil::InverseMapQuadToLocalSpace(
+ const gfx::Transform& device_transform,
+ const gfx::QuadF& device_quad) {
+ gfx::Transform inverse_device_transform(gfx::Transform::kSkipInitialization);
+ DCHECK(device_transform.IsInvertible());
+ bool did_invert = device_transform.GetInverse(&inverse_device_transform);
+ DCHECK(did_invert);
+ bool clipped = false;
+ gfx::QuadF local_quad =
+ MathUtil::MapQuad(inverse_device_transform, device_quad, &clipped);
+ // We should not DCHECK(!clipped) here, because anti-aliasing inflation may
+ // cause device_quad to become clipped. To our knowledge this scenario does
+ // not need to be handled differently than the unclipped case.
+ return local_quad;
+}
+
gfx::Rect MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
const gfx::Transform& transform,
const gfx::Rect& rect) {
diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h
index 240f1642a8c..fd9855f8bbb 100644
--- a/chromium/cc/base/math_util.h
+++ b/chromium/cc/base/math_util.h
@@ -159,6 +159,13 @@ class CC_BASE_EXPORT MathUtil {
static gfx::RectF ProjectClippedRect(const gfx::Transform& transform,
const gfx::RectF& rect);
+ // Map device space quad to local space. Device_transform has no 3d
+ // component since it was flattened, so we don't need to project. We should
+ // have already checked that the transform was invertible before this call.
+ static gfx::QuadF InverseMapQuadToLocalSpace(
+ const gfx::Transform& device_transform,
+ const gfx::QuadF& device_quad);
+
// This function is only valid when the transform preserves 2d axis
// alignment and the resulting rect will not be clipped.
static gfx::Rect MapEnclosedRectWith2dAxisAlignedTransform(
diff --git a/chromium/cc/base/rtree.h b/chromium/cc/base/rtree.h
index e71f615068e..d6a1e8d8da8 100644
--- a/chromium/cc/base/rtree.h
+++ b/chromium/cc/base/rtree.h
@@ -71,6 +71,10 @@ class RTree {
// Returns the total bounds of all items in this rtree.
gfx::Rect GetBounds() const;
+ // Returns respective bounds of all items in this rtree in the order of items.
+ // Production code except tracing should not use this method.
+ std::vector<gfx::Rect> GetAllBoundsForTracing() const;
+
void Reset();
private:
@@ -118,6 +122,9 @@ class RTree {
Branch<T> BuildRecursive(std::vector<Branch<T>>* branches, int level);
Node<T>* AllocateNodeAtLevel(int level);
+ void GetAllBoundsRecursive(Node<T>* root,
+ std::vector<gfx::Rect>* results) const;
+
// This is the count of data elements (rather than total nodes in the tree)
size_t num_data_elements_ = 0u;
Branch<T> root_;
@@ -330,6 +337,25 @@ gfx::Rect RTree<T>::GetBounds() const {
}
template <typename T>
+std::vector<gfx::Rect> RTree<T>::GetAllBoundsForTracing() const {
+ std::vector<gfx::Rect> results;
+ if (num_data_elements_ > 0)
+ GetAllBoundsRecursive(root_.subtree, &results);
+ return results;
+}
+
+template <typename T>
+void RTree<T>::GetAllBoundsRecursive(Node<T>* node,
+ std::vector<gfx::Rect>* results) const {
+ for (uint16_t i = 0; i < node->num_children; ++i) {
+ if (node->level == 0)
+ results->push_back(node->children[i].bounds);
+ else
+ GetAllBoundsRecursive(node->children[i].subtree, results);
+ }
+}
+
+template <typename T>
void RTree<T>::Reset() {
num_data_elements_ = 0;
nodes_.clear();
diff --git a/chromium/cc/base/rtree_unittest.cc b/chromium/cc/base/rtree_unittest.cc
index 683bbb3f37f..d5242a1a4aa 100644
--- a/chromium/cc/base/rtree_unittest.cc
+++ b/chromium/cc/base/rtree_unittest.cc
@@ -110,6 +110,7 @@ TEST(RTreeTest, SortedResults) {
TEST(RTreeTest, GetBoundsEmpty) {
RTree<size_t> rtree;
EXPECT_EQ(gfx::Rect(), rtree.GetBounds());
+ EXPECT_TRUE(rtree.GetAllBoundsForTracing().empty());
}
TEST(RTreeTest, GetBoundsNonOverlapping) {
@@ -121,6 +122,7 @@ TEST(RTreeTest, GetBoundsNonOverlapping) {
rtree.Build(rects);
EXPECT_EQ(gfx::Rect(5, 6, 19, 20), rtree.GetBounds());
+ EXPECT_EQ(rects, rtree.GetAllBoundsForTracing());
}
TEST(RTreeTest, GetBoundsOverlapping) {
@@ -132,6 +134,7 @@ TEST(RTreeTest, GetBoundsOverlapping) {
rtree.Build(rects);
EXPECT_EQ(gfx::Rect(0, 0, 10, 10), rtree.GetBounds());
+ EXPECT_EQ(rects, rtree.GetAllBoundsForTracing());
}
TEST(RTreeTest, BuildAfterReset) {
@@ -147,10 +150,12 @@ TEST(RTreeTest, BuildAfterReset) {
// Resetting should give the same as an empty rtree.
rtree.Reset();
EXPECT_EQ(gfx::Rect(), rtree.GetBounds());
+ EXPECT_TRUE(rtree.GetAllBoundsForTracing().empty());
// Should be able to rebuild from a reset rtree.
rtree.Build(rects);
EXPECT_EQ(gfx::Rect(0, 0, 10, 10), rtree.GetBounds());
+ EXPECT_EQ(rects, rtree.GetAllBoundsForTracing());
}
TEST(RTreeTest, Payload) {
diff --git a/chromium/cc/benchmarks/invalidation_benchmark.cc b/chromium/cc/benchmarks/invalidation_benchmark.cc
index 173df8ebdab..81ce31b3546 100644
--- a/chromium/cc/benchmarks/invalidation_benchmark.cc
+++ b/chromium/cc/benchmarks/invalidation_benchmark.cc
@@ -9,7 +9,6 @@
#include <algorithm>
#include <limits>
-#include "base/memory/ptr_util.h"
#include "base/rand_util.h"
#include "base/values.h"
#include "cc/layers/layer.h"
diff --git a/chromium/cc/benchmarks/micro_benchmark_controller.cc b/chromium/cc/benchmarks/micro_benchmark_controller.cc
index 57758adf228..3c1b166ac47 100644
--- a/chromium/cc/benchmarks/micro_benchmark_controller.cc
+++ b/chromium/cc/benchmarks/micro_benchmark_controller.cc
@@ -8,7 +8,6 @@
#include <string>
#include "base/callback.h"
-#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc b/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc
index c983cda1cde..5d1afd1357b 100644
--- a/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc
+++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc
@@ -98,8 +98,12 @@ void RasterizeAndRecordBenchmark::DidUpdateLayers(
DCHECK(!results_.get());
results_ = base::WrapUnique(new base::DictionaryValue);
results_->SetInteger("pixels_recorded", record_results_.pixels_recorded);
- results_->SetInteger("picture_memory_usage",
- static_cast<int>(record_results_.bytes_used));
+ results_->SetInteger("painter_memory_usage",
+ static_cast<int>(record_results_.painter_memory_usage));
+ results_->SetInteger("paint_op_memory_usage",
+ static_cast<int>(record_results_.paint_op_memory_usage));
+ results_->SetInteger("paint_op_count",
+ static_cast<int>(record_results_.paint_op_count));
for (int i = 0; i < RecordingSource::RECORDING_MODE_COUNT; i++) {
std::string name = base::StringPrintf("record_time%s_ms", kModeSuffixes[i]);
@@ -146,7 +150,8 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
RecordingModeToPaintingControlSetting(
static_cast<RecordingSource::RecordingMode>(mode_index));
base::TimeDelta min_time = base::TimeDelta::Max();
- size_t memory_used = 0;
+ size_t paint_op_memory_usage = 0;
+ size_t paint_op_count = 0;
scoped_refptr<DisplayItemList> display_list;
for (int i = 0; i < record_repeat_count_; ++i) {
@@ -162,11 +167,13 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
display_list, painter->GetApproximateUnsharedMemoryUsage(),
layer_tree_host_->recording_scale_factor());
- if (memory_used) {
+ if (paint_op_memory_usage) {
// Verify we are recording the same thing each time.
- DCHECK_EQ(memory_used, display_list->BytesUsed());
+ DCHECK_EQ(paint_op_memory_usage, display_list->BytesUsed());
+ DCHECK_EQ(paint_op_count, display_list->TotalOpCount());
} else {
- memory_used = display_list->BytesUsed();
+ paint_op_memory_usage = display_list->BytesUsed();
+ paint_op_count = display_list->TotalOpCount();
}
timer.NextLap();
@@ -178,8 +185,10 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
}
if (mode_index == RecordingSource::RECORD_NORMALLY) {
- record_results_.bytes_used +=
- memory_used + painter->GetApproximateUnsharedMemoryUsage();
+ record_results_.painter_memory_usage +=
+ painter->GetApproximateUnsharedMemoryUsage();
+ record_results_.paint_op_memory_usage += paint_op_memory_usage;
+ record_results_.paint_op_count += paint_op_count;
record_results_.pixels_recorded += painter->PaintableRegion().width() *
painter->PaintableRegion().height();
}
@@ -187,9 +196,7 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
}
}
-RasterizeAndRecordBenchmark::RecordResults::RecordResults()
- : pixels_recorded(0), bytes_used(0) {}
-
+RasterizeAndRecordBenchmark::RecordResults::RecordResults() = default;
RasterizeAndRecordBenchmark::RecordResults::~RecordResults() = default;
} // namespace cc
diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark.h b/chromium/cc/benchmarks/rasterize_and_record_benchmark.h
index 9e865cee45e..efb6266b9fb 100644
--- a/chromium/cc/benchmarks/rasterize_and_record_benchmark.h
+++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark.h
@@ -45,8 +45,10 @@ class RasterizeAndRecordBenchmark : public MicroBenchmark {
RecordResults();
~RecordResults();
- int pixels_recorded;
- size_t bytes_used;
+ int pixels_recorded = 0;
+ size_t painter_memory_usage = 0;
+ size_t paint_op_memory_usage = 0;
+ size_t paint_op_count = 0;
base::TimeDelta total_best_time[RecordingSource::RECORDING_MODE_COUNT];
};
diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
index 48b578f5b1b..e4d5e25a8aa 100644
--- a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
+++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
@@ -153,8 +153,6 @@ void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit(
std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
result->SetDouble("rasterize_time_ms",
rasterize_results_.total_best_time.InMillisecondsF());
- result->SetDouble("total_pictures_in_pile_size",
- static_cast<int>(rasterize_results_.total_memory_usage));
result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized);
result->SetInteger("pixels_rasterized_with_non_solid_color",
rasterize_results_.pixels_rasterized_with_non_solid_color);
@@ -191,7 +189,8 @@ void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) {
const LayerTreeSettings& settings = layer->layer_tree_impl()->settings();
std::unique_ptr<PictureLayerTilingSet> tiling_set =
PictureLayerTilingSet::Create(
- layer->GetTree(), &client, settings.tiling_interest_area_padding,
+ layer->IsActive() ? ACTIVE_TREE : PENDING_TREE, &client,
+ settings.tiling_interest_area_padding,
settings.skewport_target_time_in_seconds,
settings.skewport_extrapolation_limit_in_screen_pixels,
settings.max_preraster_distance_in_screen_pixels);
@@ -225,17 +224,12 @@ void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) {
rasterize_results_.pixels_rasterized += tile_size;
rasterize_results_.total_best_time += min_time;
}
-
- const RasterSource* layer_raster_source = layer->GetRasterSource();
- rasterize_results_.total_memory_usage +=
- layer_raster_source->GetMemoryUsage();
}
RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults()
: pixels_rasterized(0),
pixels_rasterized_with_non_solid_color(0),
pixels_rasterized_as_opaque(0),
- total_memory_usage(0),
total_layers(0),
total_picture_layers(0),
total_picture_layers_with_no_content(0),
diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.h b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.h
index 5c224da62e6..be8a6de987c 100644
--- a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.h
+++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.h
@@ -42,7 +42,6 @@ class RasterizeAndRecordBenchmarkImpl : public MicroBenchmarkImpl {
int pixels_rasterized_with_non_solid_color;
int pixels_rasterized_as_opaque;
base::TimeDelta total_best_time;
- size_t total_memory_usage;
int total_layers;
int total_picture_layers;
int total_picture_layers_with_no_content;
diff --git a/chromium/cc/blink/BUILD.gn b/chromium/cc/blink/BUILD.gn
index 31c054800a8..8b48a4097a7 100644
--- a/chromium/cc/blink/BUILD.gn
+++ b/chromium/cc/blink/BUILD.gn
@@ -41,7 +41,7 @@ cc_component("blink") {
"//cc",
"//cc/paint",
"//gpu",
- "//third_party/WebKit/public:blink",
+ "//third_party/blink/public:blink",
"//ui/gfx",
"//ui/gfx/geometry",
]
@@ -68,7 +68,7 @@ cc_test("cc_blink_unittests") {
"//skia",
"//testing/gmock",
"//testing/gtest",
- "//third_party/WebKit/public:blink",
+ "//third_party/blink/public:blink",
"//ui/gfx:test_support",
"//ui/gfx/geometry",
]
diff --git a/chromium/cc/blink/DEPS b/chromium/cc/blink/DEPS
index 3054d92a649..fc25dd99ad3 100644
--- a/chromium/cc/blink/DEPS
+++ b/chromium/cc/blink/DEPS
@@ -1,3 +1,3 @@
include_rules = [
- "+third_party/WebKit/public/platform"
+ "+third_party/blink/public/platform"
]
diff --git a/chromium/cc/blink/scrollbar_impl.cc b/chromium/cc/blink/scrollbar_impl.cc
index 0ed7a3377a7..f92b4acb522 100644
--- a/chromium/cc/blink/scrollbar_impl.cc
+++ b/chromium/cc/blink/scrollbar_impl.cc
@@ -5,8 +5,8 @@
#include "cc/blink/scrollbar_impl.h"
#include "base/logging.h"
-#include "third_party/WebKit/public/platform/WebScrollbar.h"
-#include "third_party/WebKit/public/platform/WebScrollbarThemeGeometry.h"
+#include "third_party/blink/public/platform/web_scrollbar.h"
+#include "third_party/blink/public/platform/web_scrollbar_theme_geometry.h"
using blink::WebScrollbar;
@@ -84,6 +84,10 @@ gfx::Rect ScrollbarImpl::NinePatchThumbAperture() const {
return geometry_->NinePatchThumbAperture(scrollbar_.get());
}
+bool ScrollbarImpl::HasTickmarks() const {
+ return scrollbar_->HasTickmarks();
+}
+
void ScrollbarImpl::PaintPart(cc::PaintCanvas* canvas,
cc::ScrollbarPart part,
const gfx::Rect& content_rect) {
@@ -92,6 +96,11 @@ void ScrollbarImpl::PaintPart(cc::PaintCanvas* canvas,
return;
}
+ if (part == cc::TICKMARKS) {
+ painter_.PaintTickmarks(canvas, content_rect);
+ return;
+ }
+
// The following is a simplification of ScrollbarThemeComposite::paint.
painter_.PaintScrollbarBackground(canvas, content_rect);
diff --git a/chromium/cc/blink/scrollbar_impl.h b/chromium/cc/blink/scrollbar_impl.h
index c0534d5b5e7..40157360fc8 100644
--- a/chromium/cc/blink/scrollbar_impl.h
+++ b/chromium/cc/blink/scrollbar_impl.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "cc/input/scrollbar.h"
#include "cc/paint/paint_canvas.h"
-#include "third_party/WebKit/public/platform/WebScrollbarThemePainter.h"
+#include "third_party/blink/public/platform/web_scrollbar_theme_painter.h"
namespace blink {
class WebScrollbar;
@@ -37,6 +37,7 @@ class ScrollbarImpl : public cc::Scrollbar {
gfx::Rect TrackRect() const override;
float ThumbOpacity() const override;
bool NeedsPaintPart(cc::ScrollbarPart part) const override;
+ bool HasTickmarks() const override;
void PaintPart(cc::PaintCanvas* canvas,
cc::ScrollbarPart part,
const gfx::Rect& content_rect) override;
diff --git a/chromium/cc/blink/web_blend_mode.h b/chromium/cc/blink/web_blend_mode.h
index 8d39804fa61..998868c299e 100644
--- a/chromium/cc/blink/web_blend_mode.h
+++ b/chromium/cc/blink/web_blend_mode.h
@@ -5,7 +5,7 @@
#ifndef CC_BLINK_WEB_BLEND_MODE_H_
#define CC_BLINK_WEB_BLEND_MODE_H_
-#include "third_party/WebKit/public/platform/WebBlendMode.h"
+#include "third_party/blink/public/platform/web_blend_mode.h"
#include "third_party/skia/include/core/SkBlendMode.h"
namespace cc_blink {
diff --git a/chromium/cc/blink/web_compositor_support_impl.cc b/chromium/cc/blink/web_compositor_support_impl.cc
index c3874e45e0d..04d038b181b 100644
--- a/chromium/cc/blink/web_compositor_support_impl.cc
+++ b/chromium/cc/blink/web_compositor_support_impl.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/memory/ptr_util.h"
#include "cc/blink/web_content_layer_impl.h"
#include "cc/blink/web_display_item_list_impl.h"
#include "cc/blink/web_external_texture_layer_impl.h"
diff --git a/chromium/cc/blink/web_compositor_support_impl.h b/chromium/cc/blink/web_compositor_support_impl.h
index 46748bdcbe7..9a24211b9a2 100644
--- a/chromium/cc/blink/web_compositor_support_impl.h
+++ b/chromium/cc/blink/web_compositor_support_impl.h
@@ -8,9 +8,9 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "cc/blink/cc_blink_export.h"
-#include "third_party/WebKit/public/platform/WebCompositorSupport.h"
-#include "third_party/WebKit/public/platform/WebContentLayerClient.h"
-#include "third_party/WebKit/public/platform/WebLayer.h"
+#include "third_party/blink/public/platform/web_compositor_support.h"
+#include "third_party/blink/public/platform/web_content_layer_client.h"
+#include "third_party/blink/public/platform/web_layer.h"
namespace cc_blink {
diff --git a/chromium/cc/blink/web_content_layer_impl.cc b/chromium/cc/blink/web_content_layer_impl.cc
index c72dffe6584..5dc2f9c2d81 100644
--- a/chromium/cc/blink/web_content_layer_impl.cc
+++ b/chromium/cc/blink/web_content_layer_impl.cc
@@ -7,15 +7,14 @@
#include <stddef.h>
#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
#include "cc/base/switches.h"
#include "cc/blink/web_display_item_list_impl.h"
#include "cc/layers/picture_layer.h"
-#include "third_party/WebKit/public/platform/WebContentLayerClient.h"
-#include "third_party/WebKit/public/platform/WebFloatPoint.h"
-#include "third_party/WebKit/public/platform/WebFloatRect.h"
-#include "third_party/WebKit/public/platform/WebRect.h"
-#include "third_party/WebKit/public/platform/WebSize.h"
+#include "third_party/blink/public/platform/web_content_layer_client.h"
+#include "third_party/blink/public/platform/web_float_point.h"
+#include "third_party/blink/public/platform/web_float_rect.h"
+#include "third_party/blink/public/platform/web_rect.h"
+#include "third_party/blink/public/platform/web_size.h"
#include "third_party/skia/include/core/SkMatrix44.h"
using cc::PictureLayer;
diff --git a/chromium/cc/blink/web_content_layer_impl.h b/chromium/cc/blink/web_content_layer_impl.h
index 046b79d0e64..6f82ec478e9 100644
--- a/chromium/cc/blink/web_content_layer_impl.h
+++ b/chromium/cc/blink/web_content_layer_impl.h
@@ -13,7 +13,7 @@
#include "cc/blink/cc_blink_export.h"
#include "cc/blink/web_layer_impl.h"
#include "cc/layers/content_layer_client.h"
-#include "third_party/WebKit/public/platform/WebContentLayer.h"
+#include "third_party/blink/public/platform/web_content_layer.h"
namespace blink {
class WebContentLayerClient;
diff --git a/chromium/cc/blink/web_display_item_list_impl.cc b/chromium/cc/blink/web_display_item_list_impl.cc
index 0c4c2ea81de..5be83ce9a64 100644
--- a/chromium/cc/blink/web_display_item_list_impl.cc
+++ b/chromium/cc/blink/web_display_item_list_impl.cc
@@ -12,8 +12,8 @@
#include "cc/paint/paint_filter.h"
#include "cc/paint/paint_op_buffer.h"
#include "cc/paint/render_surface_filters.h"
-#include "third_party/WebKit/public/platform/WebFloatRect.h"
-#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/blink/public/platform/web_float_rect.h"
+#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -84,7 +84,7 @@ void WebDisplayItemListImpl::AppendEndClipPathItem() {
void WebDisplayItemListImpl::AppendFloatClipItem(
const blink::WebFloatRect& clip_rect) {
- bool antialias = false;
+ bool antialias = true;
display_item_list_->StartPaint();
display_item_list_->push<cc::SaveOp>();
display_item_list_->push<cc::ClipRectOp>(gfx::RectFToSkRect(clip_rect),
diff --git a/chromium/cc/blink/web_display_item_list_impl.h b/chromium/cc/blink/web_display_item_list_impl.h
index de666a0dde3..5db188c85c8 100644
--- a/chromium/cc/blink/web_display_item_list_impl.h
+++ b/chromium/cc/blink/web_display_item_list_impl.h
@@ -9,8 +9,8 @@
#include "base/memory/ref_counted.h"
#include "cc/blink/cc_blink_export.h"
#include "cc/paint/display_item_list.h"
-#include "third_party/WebKit/public/platform/WebDisplayItemList.h"
-#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/blink/public/platform/web_display_item_list.h"
+#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "ui/gfx/geometry/point_f.h"
diff --git a/chromium/cc/blink/web_display_item_list_impl_unittest.cc b/chromium/cc/blink/web_display_item_list_impl_unittest.cc
index 5d920c13e92..f9efd761eed 100644
--- a/chromium/cc/blink/web_display_item_list_impl_unittest.cc
+++ b/chromium/cc/blink/web_display_item_list_impl_unittest.cc
@@ -7,7 +7,7 @@
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_op_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebFloatPoint.h"
+#include "third_party/blink/public/platform/web_float_point.h"
namespace cc_blink {
namespace {
diff --git a/chromium/cc/blink/web_external_texture_layer_impl.cc b/chromium/cc/blink/web_external_texture_layer_impl.cc
index b6d042bce5c..64fbf26cbd4 100644
--- a/chromium/cc/blink/web_external_texture_layer_impl.cc
+++ b/chromium/cc/blink/web_external_texture_layer_impl.cc
@@ -54,4 +54,12 @@ void WebExternalTextureLayerImpl::SetNearestNeighbor(bool nearest_neighbor) {
->SetNearestNeighbor(nearest_neighbor);
}
+void WebExternalTextureLayerImpl::SetUV(
+ const blink::WebFloatPoint left_top,
+ const blink::WebFloatPoint right_bottom) {
+ static_cast<TextureLayer*>(layer_->layer())
+ ->SetUV(gfx::PointF(left_top.x, left_top.y),
+ gfx::PointF(right_bottom.x, right_bottom.y));
+}
+
} // namespace cc_blink
diff --git a/chromium/cc/blink/web_external_texture_layer_impl.h b/chromium/cc/blink/web_external_texture_layer_impl.h
index e7bea81b8ff..11ca63cf5b1 100644
--- a/chromium/cc/blink/web_external_texture_layer_impl.h
+++ b/chromium/cc/blink/web_external_texture_layer_impl.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "cc/blink/cc_blink_export.h"
-#include "third_party/WebKit/public/platform/WebExternalTextureLayer.h"
+#include "third_party/blink/public/platform/web_external_texture_layer.h"
namespace cc {
class TextureLayerClient;
@@ -31,6 +31,8 @@ class WebExternalTextureLayerImpl : public blink::WebExternalTextureLayer {
void SetPremultipliedAlpha(bool premultiplied) override;
void SetBlendBackgroundColor(bool blend) override;
void SetNearestNeighbor(bool nearest_neighbor) override;
+ void SetUV(const blink::WebFloatPoint left_top,
+ const blink::WebFloatPoint right_bottom) override;
private:
std::unique_ptr<WebLayerImpl> layer_;
diff --git a/chromium/cc/blink/web_image_layer_impl.h b/chromium/cc/blink/web_image_layer_impl.h
index 67af12c0929..11b76dc95e7 100644
--- a/chromium/cc/blink/web_image_layer_impl.h
+++ b/chromium/cc/blink/web_image_layer_impl.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "cc/blink/cc_blink_export.h"
#include "cc/paint/paint_image.h"
-#include "third_party/WebKit/public/platform/WebImageLayer.h"
+#include "third_party/blink/public/platform/web_image_layer.h"
namespace cc_blink {
diff --git a/chromium/cc/blink/web_layer_impl.cc b/chromium/cc/blink/web_layer_impl.cc
index 4b3e0caecf5..b8cb7aeb9eb 100644
--- a/chromium/cc/blink/web_layer_impl.cc
+++ b/chromium/cc/blink/web_layer_impl.cc
@@ -24,12 +24,12 @@
#include "cc/layers/touch_action_region.h"
#include "cc/trees/element_id.h"
#include "cc/trees/layer_tree_host.h"
-#include "third_party/WebKit/public/platform/WebFloatPoint.h"
-#include "third_party/WebKit/public/platform/WebFloatRect.h"
-#include "third_party/WebKit/public/platform/WebLayerPositionConstraint.h"
-#include "third_party/WebKit/public/platform/WebLayerScrollClient.h"
-#include "third_party/WebKit/public/platform/WebLayerStickyPositionConstraint.h"
-#include "third_party/WebKit/public/platform/WebSize.h"
+#include "third_party/blink/public/platform/web_float_point.h"
+#include "third_party/blink/public/platform/web_float_rect.h"
+#include "third_party/blink/public/platform/web_layer_position_constraint.h"
+#include "third_party/blink/public/platform/web_layer_scroll_client.h"
+#include "third_party/blink/public/platform/web_layer_sticky_position_constraint.h"
+#include "third_party/blink/public/platform/web_size.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
@@ -460,8 +460,8 @@ void WebLayerImpl::SetScrollOffsetFromImplSideForTesting(
layer_->SetScrollOffsetFromImplSide(offset);
}
-void WebLayerImpl::SetLayerClient(cc::LayerClient* client) {
- layer_->SetLayerClient(client);
+void WebLayerImpl::SetLayerClient(base::WeakPtr<cc::LayerClient> client) {
+ layer_->SetLayerClient(std::move(client));
}
const cc::Layer* WebLayerImpl::CcLayer() const {
diff --git a/chromium/cc/blink/web_layer_impl.h b/chromium/cc/blink/web_layer_impl.h
index 84e3d2b6472..9be421d303f 100644
--- a/chromium/cc/blink/web_layer_impl.h
+++ b/chromium/cc/blink/web_layer_impl.h
@@ -16,16 +16,16 @@
#include "base/memory/ref_counted.h"
#include "cc/blink/cc_blink_export.h"
#include "cc/layers/layer_client.h"
-#include "third_party/WebKit/public/platform/WebColor.h"
-#include "third_party/WebKit/public/platform/WebDoublePoint.h"
-#include "third_party/WebKit/public/platform/WebFloatPoint.h"
-#include "third_party/WebKit/public/platform/WebFloatSize.h"
-#include "third_party/WebKit/public/platform/WebLayer.h"
-#include "third_party/WebKit/public/platform/WebPoint.h"
-#include "third_party/WebKit/public/platform/WebRect.h"
-#include "third_party/WebKit/public/platform/WebSize.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/blink/public/platform/web_color.h"
+#include "third_party/blink/public/platform/web_double_point.h"
+#include "third_party/blink/public/platform/web_float_point.h"
+#include "third_party/blink/public/platform/web_float_size.h"
+#include "third_party/blink/public/platform/web_layer.h"
+#include "third_party/blink/public/platform/web_point.h"
+#include "third_party/blink/public/platform/web_rect.h"
+#include "third_party/blink/public/platform/web_size.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/skia/include/core/SkMatrix44.h"
namespace cc {
@@ -122,7 +122,7 @@ class CC_BLINK_EXPORT WebLayerImpl : public blink::WebLayer {
const override;
void SetScrollClient(blink::WebLayerScrollClient* client) override;
void SetScrollOffsetFromImplSideForTesting(const gfx::ScrollOffset&) override;
- void SetLayerClient(cc::LayerClient* client) override;
+ void SetLayerClient(base::WeakPtr<cc::LayerClient> client) override;
const cc::Layer* CcLayer() const override;
cc::Layer* CcLayer() override;
void SetElementId(const cc::ElementId&) override;
diff --git a/chromium/cc/blink/web_layer_impl_fixed_bounds.cc b/chromium/cc/blink/web_layer_impl_fixed_bounds.cc
index aa6ccbcf468..dc6b90993c4 100644
--- a/chromium/cc/blink/web_layer_impl_fixed_bounds.cc
+++ b/chromium/cc/blink/web_layer_impl_fixed_bounds.cc
@@ -5,8 +5,8 @@
#include "cc/blink/web_layer_impl_fixed_bounds.h"
#include "cc/layers/layer.h"
-#include "third_party/WebKit/public/platform/WebFloatPoint.h"
-#include "third_party/WebKit/public/platform/WebSize.h"
+#include "third_party/blink/public/platform/web_float_point.h"
+#include "third_party/blink/public/platform/web_size.h"
#include "third_party/skia/include/core/SkMatrix44.h"
using cc::Layer;
diff --git a/chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc b/chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc
index 3dd88c1baa0..354326e36aa 100644
--- a/chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc
+++ b/chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc
@@ -2,17 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "cc/blink/web_layer_impl_fixed_bounds.h"
#include <vector>
#include "cc/animation/animation_host.h"
-#include "cc/blink/web_layer_impl_fixed_bounds.h"
#include "cc/layers/picture_image_layer.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_common.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebFloatPoint.h"
-#include "third_party/WebKit/public/platform/WebSize.h"
+#include "third_party/blink/public/platform/web_float_point.h"
+#include "third_party/blink/public/platform/web_size.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/geometry/point3_f.h"
diff --git a/chromium/cc/blink/web_scrollbar_layer_impl.cc b/chromium/cc/blink/web_scrollbar_layer_impl.cc
index 2a2d4e1187e..f501002d486 100644
--- a/chromium/cc/blink/web_scrollbar_layer_impl.cc
+++ b/chromium/cc/blink/web_scrollbar_layer_impl.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/memory/ptr_util.h"
#include "cc/blink/scrollbar_impl.h"
#include "cc/blink/web_layer_impl.h"
#include "cc/layers/layer.h"
diff --git a/chromium/cc/blink/web_scrollbar_layer_impl.h b/chromium/cc/blink/web_scrollbar_layer_impl.h
index e8e0fe438aa..c80c31df230 100644
--- a/chromium/cc/blink/web_scrollbar_layer_impl.h
+++ b/chromium/cc/blink/web_scrollbar_layer_impl.h
@@ -9,8 +9,8 @@
#include "base/macros.h"
#include "cc/blink/cc_blink_export.h"
-#include "third_party/WebKit/public/platform/WebScrollbar.h"
-#include "third_party/WebKit/public/platform/WebScrollbarLayer.h"
+#include "third_party/blink/public/platform/web_scrollbar.h"
+#include "third_party/blink/public/platform/web_scrollbar_layer.h"
namespace blink {
class WebScrollbarThemeGeometry;
diff --git a/chromium/cc/input/browser_controls_offset_manager_unittest.cc b/chromium/cc/input/browser_controls_offset_manager_unittest.cc
index 7f039cd66a1..098a701ece5 100644
--- a/chromium/cc/input/browser_controls_offset_manager_unittest.cc
+++ b/chromium/cc/input/browser_controls_offset_manager_unittest.cc
@@ -9,7 +9,6 @@
#include <memory>
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "cc/input/browser_controls_offset_manager_client.h"
#include "cc/layers/layer_impl.h"
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index 04c27fce4c6..312f103e941 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -49,6 +49,9 @@ struct CC_EXPORT InputHandlerScrollResult {
// How the browser should handle the overscroll navigation based on the css
// property scroll-boundary-behavior.
OverscrollBehavior overscroll_behavior;
+ // The current offset of the currently scrolling node. It is in DIP or
+ // physical pixels depending on the use-zoom-for-dsf flag.
+ gfx::Vector2dF current_offset;
};
class CC_EXPORT InputHandlerClient {
@@ -231,6 +234,16 @@ class CC_EXPORT InputHandler {
virtual bool ScrollingShouldSwitchtoMainThread() = 0;
+ // Sets the initial and target offset for scroll snapping for the currently
+ // scrolling node and the given natural displacement.
+ // |natural_displacement_in_viewport| is the estimated total scrolling for
+ // the active scroll sequence.
+ // Returns false if their is no position to snap to.
+ virtual bool GetSnapFlingInfo(
+ const gfx::Vector2dF& natural_displacement_in_viewport,
+ gfx::Vector2dF* initial_offset,
+ gfx::Vector2dF* target_offset) const = 0;
+
protected:
InputHandler() {}
virtual ~InputHandler() {}
diff --git a/chromium/cc/input/scroll_snap_data.cc b/chromium/cc/input/scroll_snap_data.cc
index 31b00d8ed15..58b225849d4 100644
--- a/chromium/cc/input/scroll_snap_data.cc
+++ b/chromium/cc/input/scroll_snap_data.cc
@@ -4,21 +4,103 @@
#include "cc/input/scroll_snap_data.h"
+#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 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.snap_axis == SnapAxis::kX ||
+ area.snap_axis == SnapAxis::kBoth
+ : area.snap_axis == SnapAxis::kY ||
+ area.snap_axis == SnapAxis::kBoth;
+}
+
+// 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;
+
+ 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;
+
+ 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;
+}
+
+} // namespace
-SnapContainerData::SnapContainerData() = default;
+SnapContainerData::SnapContainerData()
+ : proximity_range_(gfx::ScrollOffset(std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max())) {}
SnapContainerData::SnapContainerData(ScrollSnapType type)
- : scroll_snap_type_(type) {}
+ : scroll_snap_type_(type),
+ proximity_range_(gfx::ScrollOffset(std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max())) {}
SnapContainerData::SnapContainerData(ScrollSnapType type, gfx::ScrollOffset max)
- : scroll_snap_type_(type), max_position_(max) {}
+ : scroll_snap_type_(type),
+ 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() = default;
@@ -29,6 +111,7 @@ SnapContainerData& SnapContainerData::operator=(
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;
}
@@ -37,52 +120,70 @@ void SnapContainerData::AddSnapAreaData(SnapAreaData snap_area_data) {
snap_area_list_.push_back(snap_area_data);
}
-gfx::ScrollOffset SnapContainerData::FindSnapPosition(
+bool SnapContainerData::FindSnapPosition(
const gfx::ScrollOffset& current_position,
bool should_snap_on_x,
- bool should_snap_on_y) const {
+ bool should_snap_on_y,
+ gfx::ScrollOffset* snap_position) const {
SnapAxis axis = scroll_snap_type_.axis;
should_snap_on_x &= (axis == SnapAxis::kX || axis == SnapAxis::kBoth);
should_snap_on_y &= (axis == SnapAxis::kY || axis == SnapAxis::kBoth);
if (!should_snap_on_x && !should_snap_on_y)
- return current_position;
-
- float smallest_distance_x = std::numeric_limits<float>::max();
- float smallest_distance_y = std::numeric_limits<float>::max();
-
- gfx::ScrollOffset snap_position = current_position;
-
- for (const SnapAreaData& snap_area_data : snap_area_list_) {
- // TODO(sunyunjia): We should consider visiblity when choosing snap offset.
- if (should_snap_on_x && (snap_area_data.snap_axis == SnapAxis::kX ||
- snap_area_data.snap_axis == SnapAxis::kBoth)) {
- float offset = snap_area_data.snap_position.x();
- if (offset == SnapAreaData::kInvalidScrollPosition)
- continue;
- float distance = std::abs(current_position.x() - offset);
- if (distance < smallest_distance_x) {
- smallest_distance_x = distance;
- snap_position.set_x(offset);
- }
- }
- if (should_snap_on_y && (snap_area_data.snap_axis == SnapAxis::kY ||
- snap_area_data.snap_axis == SnapAxis::kBoth)) {
- float offset = snap_area_data.snap_position.y();
- if (offset == SnapAreaData::kInvalidScrollPosition)
- continue;
- float distance = std::abs(current_position.y() - offset);
- if (distance < smallest_distance_y) {
- smallest_distance_y = distance;
- snap_position.set_y(offset);
- }
+ return false;
+
+ base::Optional<SnapAreaData> 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_);
+ }
+ if (should_snap_on_y) {
+ closest_y = FindClosestValidArea(SearchAxis::kY, current_position,
+ current_position, scrollable_region,
+ proximity_range_, snap_area_list_);
+ }
+
+ if (!closest_x.has_value() && !closest_y.has_value())
+ return false;
+
+ // If snapping in one axis pushes off-screen the other snap area, this snap
+ // position is invalid. https://drafts.csswg.org/css-scroll-snap-1/#snap-scope
+ // In this case, we choose the axis whose snap area is closer, and find a
+ // mutual visible snap area on the other axis.
+ 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_);
}
}
- return snap_position;
+
+ *snap_position = current_position;
+ if (closest_x.has_value())
+ snap_position->set_x(closest_x.value().snap_position.x());
+ if (closest_y.has_value())
+ snap_position->set_y(closest_y.value().snap_position.y());
+
+ return true;
}
std::ostream& operator<<(std::ostream& ostream, const SnapAreaData& area_data) {
- return ostream << area_data.snap_position.x() << ", "
- << area_data.snap_position.y();
+ return ostream << area_data.snap_position.ToString() << "\t"
+ << "visible in: " << area_data.visible_region.ToString();
}
std::ostream& operator<<(std::ostream& ostream,
diff --git a/chromium/cc/input/scroll_snap_data.h b/chromium/cc/input/scroll_snap_data.h
index 1ae42c33405..dbc0b9128f5 100644
--- a/chromium/cc/input/scroll_snap_data.h
+++ b/chromium/cc/input/scroll_snap_data.h
@@ -8,6 +8,7 @@
#include <vector>
#include "cc/cc_export.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
namespace cc {
@@ -21,6 +22,9 @@ enum class SnapAxis : unsigned {
kInline,
};
+// A helper enum to specify the the axis when doing calculations.
+enum class SearchAxis : unsigned { kX, kY };
+
// See https://www.w3.org/TR/css-scroll-snap-1/#snap-strictness
// TODO(sunyunjia): Add kNone for SnapStrictness to match the spec.
// crbug.com/791663
@@ -58,24 +62,26 @@ struct ScrollSnapType {
struct ScrollSnapAlign {
ScrollSnapAlign()
- : alignmentX(SnapAlignment::kNone), alignmentY(SnapAlignment::kNone) {}
+ : alignment_inline(SnapAlignment::kNone),
+ alignment_block(SnapAlignment::kNone) {}
explicit ScrollSnapAlign(SnapAlignment alignment)
- : alignmentX(alignment), alignmentY(alignment) {}
+ : alignment_inline(alignment), alignment_block(alignment) {}
- ScrollSnapAlign(SnapAlignment x, SnapAlignment y)
- : alignmentX(x), alignmentY(y) {}
+ ScrollSnapAlign(SnapAlignment i, SnapAlignment b)
+ : alignment_inline(i), alignment_block(b) {}
bool operator==(const ScrollSnapAlign& other) const {
- return alignmentX == other.alignmentX && alignmentY == other.alignmentY;
+ return alignment_inline == other.alignment_inline &&
+ alignment_block == other.alignment_block;
}
bool operator!=(const ScrollSnapAlign& other) const {
return !(*this == other);
}
- SnapAlignment alignmentX;
- SnapAlignment alignmentY;
+ SnapAlignment alignment_inline;
+ SnapAlignment alignment_block;
};
// Snap area is a bounding box that could be snapped to when a scroll happens in
@@ -90,12 +96,19 @@ struct SnapAreaData {
SnapAreaData() {}
- SnapAreaData(SnapAxis axis, gfx::ScrollOffset position, bool msnap)
- : snap_axis(axis), snap_position(position), must_snap(msnap) {}
+ SnapAreaData(SnapAxis axis,
+ gfx::ScrollOffset position,
+ gfx::RectF visible,
+ bool msnap)
+ : snap_axis(axis),
+ snap_position(position),
+ visible_region(visible),
+ 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);
}
@@ -111,6 +124,11 @@ struct SnapAreaData {
// overflow rect.
gfx::ScrollOffset snap_position;
+ // 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;
+
// Whether this area has scroll-snap-stop: always.
// See https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-stop
bool must_snap;
@@ -119,6 +137,8 @@ struct SnapAreaData {
// snapping.
};
+typedef std::vector<SnapAreaData> SnapAreaList;
+
// Snap container is a scroll container that has non-'none' value for
// scroll-snap-type. It can be snapped to one of its snap areas when a scroll
// happens.
@@ -139,6 +159,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.proximity_range_ == proximity_range_) &&
(other.snap_area_list_ == snap_area_list_);
}
@@ -146,9 +167,10 @@ class CC_EXPORT SnapContainerData {
return !(*this == other);
}
- gfx::ScrollOffset FindSnapPosition(const gfx::ScrollOffset& current_position,
- bool should_snap_on_x,
- bool should_snap_on_y) const;
+ bool FindSnapPosition(const gfx::ScrollOffset& current_position,
+ bool should_snap_on_x,
+ bool should_snap_on_y,
+ gfx::ScrollOffset* snap_position) const;
void AddSnapAreaData(SnapAreaData snap_area_data);
size_t size() const { return snap_area_list_.size(); }
@@ -162,6 +184,11 @@ class CC_EXPORT SnapContainerData {
}
gfx::ScrollOffset max_position() const { return max_position_; }
+ void set_proximity_range(const gfx::ScrollOffset& range) {
+ proximity_range_ = range;
+ }
+ gfx::ScrollOffset proximity_range() const { return proximity_range_; }
+
private:
// Specifies whether a scroll container is a scroll snap container, how
// strictly it snaps, and which axes are considered.
@@ -172,6 +199,10 @@ class CC_EXPORT SnapContainerData {
// with blink's scroll position.
gfx::ScrollOffset max_position_;
+ // A valid snap position should be within the |proximity_range_| of the
+ // current offset on the snapping axis.
+ gfx::ScrollOffset proximity_range_;
+
// The SnapAreaData for the snap areas in this snap container. When a scroll
// happens, we iterate through the snap_area_list to find the best snap
// position.
diff --git a/chromium/cc/input/scroll_snap_data_unittest.cc b/chromium/cc/input/scroll_snap_data_unittest.cc
index c80fc3d92fc..794f83faeaf 100644
--- a/chromium/cc/input/scroll_snap_data_unittest.cc
+++ b/chromium/cc/input/scroll_snap_data_unittest.cc
@@ -17,16 +17,18 @@ TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionIndependently) {
gfx::ScrollOffset current_position(100, 100);
SnapAreaData snap_x_only(
SnapAxis::kX, gfx::ScrollOffset(80, SnapAreaData::kInvalidScrollPosition),
- false);
+ gfx::RectF(0, 0, 360, 380), false);
SnapAreaData snap_y_only(
SnapAxis::kY, gfx::ScrollOffset(SnapAreaData::kInvalidScrollPosition, 70),
- false);
- SnapAreaData snap_on_both(SnapAxis::kBoth, gfx::ScrollOffset(50, 150), false);
+ 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);
- gfx::ScrollOffset snap_position =
- data.FindSnapPosition(current_position, true, true);
+ gfx::ScrollOffset snap_position;
+ EXPECT_TRUE(
+ data.FindSnapPosition(current_position, true, true, &snap_position));
EXPECT_EQ(80, snap_position.x());
EXPECT_EQ(70, snap_position.y());
}
@@ -38,16 +40,18 @@ TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionOnAxisValueBoth) {
gfx::ScrollOffset current_position(40, 150);
SnapAreaData snap_x_only(
SnapAxis::kX, gfx::ScrollOffset(80, SnapAreaData::kInvalidScrollPosition),
- false);
+ gfx::RectF(0, 0, 360, 380), false);
SnapAreaData snap_y_only(
SnapAxis::kY, gfx::ScrollOffset(SnapAreaData::kInvalidScrollPosition, 70),
- false);
- SnapAreaData snap_on_both(SnapAxis::kBoth, gfx::ScrollOffset(50, 150), false);
+ 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);
- gfx::ScrollOffset snap_position =
- data.FindSnapPosition(current_position, true, true);
+ gfx::ScrollOffset snap_position;
+ EXPECT_TRUE(
+ data.FindSnapPosition(current_position, true, true, &snap_position));
EXPECT_EQ(50, snap_position.x());
EXPECT_EQ(150, snap_position.y());
}
@@ -59,14 +63,83 @@ TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonScrolledAxis) {
gfx::ScrollOffset current_position(100, 100);
SnapAreaData snap_x_only(
SnapAxis::kX, gfx::ScrollOffset(80, SnapAreaData::kInvalidScrollPosition),
- false);
+ gfx::RectF(0, 0, 360, 380), false);
SnapAreaData snap_y_only(
SnapAxis::kY, gfx::ScrollOffset(SnapAreaData::kInvalidScrollPosition, 70),
- false);
+ gfx::RectF(0, 0, 360, 380), false);
data.AddSnapAreaData(snap_x_only);
data.AddSnapAreaData(snap_y_only);
- gfx::ScrollOffset snap_position =
- data.FindSnapPosition(current_position, true, false);
+ gfx::ScrollOffset snap_position;
+ EXPECT_TRUE(
+ data.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(
+ 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::ScrollOffset snap_position;
+ EXPECT_FALSE(
+ data.FindSnapPosition(current_position, true, true, &snap_position));
+}
+
+TEST_F(ScrollSnapDataTest, SnapOnClosestAxisFirstIfVisibilityConflicts) {
+ SnapContainerData data(
+ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
+ gfx::ScrollOffset(360, 380));
+ gfx::ScrollOffset current_position(100, 100);
+
+ // Both the areas are currently visible.
+ // However, if we snap to them on x and y independently, none is visible after
+ // snapping. So we only snap on the axis that has a closer snap point first.
+ // 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);
+ SnapAreaData snap_y1(
+ SnapAxis::kY,
+ gfx::ScrollOffset(SnapAreaData::kInvalidScrollPosition, 130),
+ gfx::RectF(90, 90, 60, 60), 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);
+ 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());
+}
+
+TEST_F(ScrollSnapDataTest, DoesNotSnapToPositionsOutsideProximityRange) {
+ SnapContainerData data(
+ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
+ gfx::ScrollOffset(360, 380));
+ data.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);
+ gfx::ScrollOffset snap_position;
+ EXPECT_TRUE(
+ data.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
+ // [50, 150], so we should only snap on x.
EXPECT_EQ(80, snap_position.x());
EXPECT_EQ(100, snap_position.y());
}
diff --git a/chromium/cc/input/scrollbar.h b/chromium/cc/input/scrollbar.h
index e0302bffcb6..ab67bce81c0 100644
--- a/chromium/cc/input/scrollbar.h
+++ b/chromium/cc/input/scrollbar.h
@@ -16,7 +16,7 @@ enum ScrollbarOrientation { HORIZONTAL, VERTICAL };
enum ScrollDirection { SCROLL_BACKWARD, SCROLL_FORWARD };
// For now, TRACK includes everything but the thumb including background and
// buttons.
-enum ScrollbarPart { THUMB, TRACK };
+enum ScrollbarPart { THUMB, TRACK, TICKMARKS };
class Scrollbar {
public:
@@ -31,6 +31,7 @@ class Scrollbar {
virtual int ThumbLength() const = 0;
virtual gfx::Rect TrackRect() const = 0;
virtual float ThumbOpacity() const = 0;
+ virtual bool HasTickmarks() const = 0;
virtual bool NeedsPaintPart(ScrollbarPart part) const = 0;
virtual void PaintPart(PaintCanvas* canvas,
ScrollbarPart part,
diff --git a/chromium/cc/input/scrollbar_animation_controller.cc b/chromium/cc/input/scrollbar_animation_controller.cc
index 0ee16d510ed..55f97f09d1f 100644
--- a/chromium/cc/input/scrollbar_animation_controller.cc
+++ b/chromium/cc/input/scrollbar_animation_controller.cc
@@ -54,6 +54,7 @@ ScrollbarAnimationController::ScrollbarAnimationController(
show_scrollbars_on_scroll_gesture_(false),
need_thinning_animation_(false),
is_mouse_down_(false),
+ tickmarks_showing_(false),
weak_factory_(this) {}
ScrollbarAnimationController::ScrollbarAnimationController(
@@ -76,6 +77,7 @@ ScrollbarAnimationController::ScrollbarAnimationController(
show_scrollbars_on_scroll_gesture_(true),
need_thinning_animation_(true),
is_mouse_down_(false),
+ tickmarks_showing_(false),
weak_factory_(this) {
vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create(
scroll_element_id, ScrollbarOrientation::VERTICAL, client,
@@ -194,11 +196,15 @@ void ScrollbarAnimationController::DidScrollEnd() {
if (need_thinning_animation_ && MouseIsNearAnyScrollbar())
return;
- if (has_scrolled)
+ if (has_scrolled && !tickmarks_showing_)
PostDelayedAnimation(FADE_OUT);
}
void ScrollbarAnimationController::DidScrollUpdate() {
+ UpdateScrollbarState();
+}
+
+void ScrollbarAnimationController::UpdateScrollbarState() {
if (need_thinning_animation_ && Captured())
return;
@@ -209,10 +215,14 @@ void ScrollbarAnimationController::DidScrollUpdate() {
// As an optimization, we avoid spamming fade delay tasks during active fast
// scrolls. But if we're not within one, we need to post every scroll update.
if (!currently_scrolling_) {
- // We don't fade out scrollbar if they need thinning animation and mouse is
- // near.
- if (!need_thinning_animation_ || !MouseIsNearAnyScrollbar())
+ // We don't fade out scrollbar if they need thinning animation (Aura
+ // Overlay) and mouse is near or tickmarks show.
+ if (need_thinning_animation_) {
+ if (!MouseIsNearAnyScrollbar() && !tickmarks_showing_)
+ PostDelayedAnimation(FADE_OUT);
+ } else {
PostDelayedAnimation(FADE_OUT);
+ }
} else {
show_in_fast_scroll_ = true;
}
@@ -225,11 +235,22 @@ void ScrollbarAnimationController::DidScrollUpdate() {
void ScrollbarAnimationController::WillUpdateScroll() {
if (show_scrollbars_on_scroll_gesture_)
- DidScrollUpdate();
+ UpdateScrollbarState();
}
void ScrollbarAnimationController::DidRequestShowFromMainThread() {
- DidScrollUpdate();
+ UpdateScrollbarState();
+}
+
+void ScrollbarAnimationController::UpdateTickmarksVisibility(bool show) {
+ if (!need_thinning_animation_)
+ return;
+
+ if (tickmarks_showing_ == show)
+ return;
+
+ tickmarks_showing_ = show;
+ UpdateScrollbarState();
}
void ScrollbarAnimationController::DidMouseDown() {
@@ -267,7 +288,7 @@ void ScrollbarAnimationController::DidMouseUp() {
vertical_controller_->DidMouseUp();
horizontal_controller_->DidMouseUp();
- if (!MouseIsNearAnyScrollbar() && !ScrollbarsHidden())
+ if (!MouseIsNearAnyScrollbar() && !ScrollbarsHidden() && !tickmarks_showing_)
PostDelayedAnimation(FADE_OUT);
}
@@ -281,7 +302,7 @@ void ScrollbarAnimationController::DidMouseLeave() {
delayed_scrollbar_animation_.Cancel();
need_trigger_scrollbar_fade_in_ = false;
- if (ScrollbarsHidden() || Captured())
+ if (ScrollbarsHidden() || Captured() || tickmarks_showing_)
return;
PostDelayedAnimation(FADE_OUT);
@@ -297,7 +318,7 @@ void ScrollbarAnimationController::DidMouseMove(
vertical_controller_->DidMouseMove(device_viewport_point);
horizontal_controller_->DidMouseMove(device_viewport_point);
- if (Captured()) {
+ if (Captured() || tickmarks_showing_) {
DCHECK(!ScrollbarsHidden());
return;
}
diff --git a/chromium/cc/input/scrollbar_animation_controller.h b/chromium/cc/input/scrollbar_animation_controller.h
index 64bf2b6ac06..9473b416bf8 100644
--- a/chromium/cc/input/scrollbar_animation_controller.h
+++ b/chromium/cc/input/scrollbar_animation_controller.h
@@ -84,6 +84,8 @@ class CC_EXPORT ScrollbarAnimationController {
// ScrollableArea::showOverlayScrollbars).
void DidRequestShowFromMainThread();
+ void UpdateTickmarksVisibility(bool show);
+
// These methods are public for testing.
bool MouseIsOverScrollbarThumb(ScrollbarOrientation orientation) const;
bool MouseIsNearScrollbarThumb(ScrollbarOrientation orientation) const;
@@ -114,6 +116,10 @@ class CC_EXPORT ScrollbarAnimationController {
SingleScrollbarAnimationControllerThinning& GetScrollbarAnimationController(
ScrollbarOrientation) const;
+ // Any scrollbar state update would show scrollbar hen post the delay fade out
+ // if needed.
+ void UpdateScrollbarState();
+
// Returns how far through the animation we are as a progress value from
// 0 to 1.
float AnimationProgressAtTime(base::TimeTicks now);
@@ -156,6 +162,8 @@ class CC_EXPORT ScrollbarAnimationController {
bool is_mouse_down_;
+ bool tickmarks_showing_;
+
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
vertical_controller_;
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
diff --git a/chromium/cc/input/scrollbar_animation_controller_unittest.cc b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
index b142096e58b..9749fc77148 100644
--- a/chromium/cc/input/scrollbar_animation_controller_unittest.cc
+++ b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
@@ -1318,6 +1318,54 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
client_.start_fade().IsCancelled());
}
+// Ensure Aura Overlay Scrollbars shows and did not fade out when tickmarks show
+// and fade out when tickmarks hide.
+TEST_F(ScrollbarAnimationControllerAuraOverlayTest, TickmakrsShowHide) {
+ base::TimeTicks time;
+ time += base::TimeDelta::FromSeconds(1);
+
+ // Overlay Scrollbar hidden at beginnging.
+ EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden());
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Scrollbars show when tickmarks show.
+ scrollbar_controller_->UpdateTickmarksVisibility(true);
+ EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Scroll update, no delay fade animation.
+ scrollbar_controller_->DidScrollUpdate();
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Scroll update with phase, no delay fade animation.
+ scrollbar_controller_->DidScrollBegin();
+ scrollbar_controller_->DidScrollUpdate();
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+ scrollbar_controller_->DidScrollEnd();
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Move mouse, no delay fade animation.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0));
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Mouse leave, no delay fade animation.
+ scrollbar_controller_->DidMouseLeave();
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Scrollbars fade out animation has enqueued when tickmarks hide.
+ scrollbar_controller_->UpdateTickmarksVisibility(false);
+ EXPECT_FALSE(client_.start_fade().is_null());
+ EXPECT_FALSE(client_.start_fade().IsCancelled());
+ EXPECT_EQ(kFadeDelay, client_.delay());
+}
+
class ScrollbarAnimationControllerAndroidTest
: public testing::Test,
public ScrollbarAnimationControllerClient {
diff --git a/chromium/cc/ipc/cc_param_traits.cc b/chromium/cc/ipc/cc_param_traits.cc
index c9ad471b488..c66518e291d 100644
--- a/chromium/cc/ipc/cc_param_traits.cc
+++ b/chromium/cc/ipc/cc_param_traits.cc
@@ -675,7 +675,7 @@ void ParamTraits<viz::LocalSurfaceId>::Write(base::Pickle* m,
DCHECK(p.is_valid());
WriteParam(m, p.parent_sequence_number());
WriteParam(m, p.child_sequence_number());
- WriteParam(m, p.nonce());
+ WriteParam(m, p.embed_token());
}
bool ParamTraits<viz::LocalSurfaceId>::Read(const base::Pickle* m,
@@ -689,12 +689,12 @@ bool ParamTraits<viz::LocalSurfaceId>::Read(const base::Pickle* m,
if (!ReadParam(m, iter, &child_sequence_number))
return false;
- base::UnguessableToken nonce;
- if (!ReadParam(m, iter, &nonce))
+ base::UnguessableToken embed_token;
+ if (!ReadParam(m, iter, &embed_token))
return false;
- *p =
- viz::LocalSurfaceId(parent_sequence_number, child_sequence_number, nonce);
+ *p = viz::LocalSurfaceId(parent_sequence_number, child_sequence_number,
+ embed_token);
return p->is_valid();
}
@@ -705,7 +705,7 @@ void ParamTraits<viz::LocalSurfaceId>::Log(const param_type& p,
l->append(", ");
LogParam(p.child_sequence_number(), l);
l->append(", ");
- LogParam(p.nonce(), l);
+ LogParam(p.embed_token(), l);
l->append(")");
}
diff --git a/chromium/cc/ipc/cc_param_traits_macros.h b/chromium/cc/ipc/cc_param_traits_macros.h
index 181295889cc..1141b237a82 100644
--- a/chromium/cc/ipc/cc_param_traits_macros.h
+++ b/chromium/cc/ipc/cc_param_traits_macros.h
@@ -117,6 +117,7 @@ IPC_STRUCT_TRAITS_BEGIN(viz::TileDrawQuad)
IPC_STRUCT_TRAITS_MEMBER(tex_coord_rect)
IPC_STRUCT_TRAITS_MEMBER(texture_size)
IPC_STRUCT_TRAITS_MEMBER(swizzle_contents)
+ IPC_STRUCT_TRAITS_MEMBER(is_premultiplied)
IPC_STRUCT_TRAITS_MEMBER(nearest_neighbor)
IPC_STRUCT_TRAITS_MEMBER(force_anti_aliasing_off)
IPC_STRUCT_TRAITS_END()
diff --git a/chromium/cc/ipc/cc_param_traits_unittest.cc b/chromium/cc/ipc/cc_param_traits_unittest.cc
index 97e58901e1c..867bb9c39b0 100644
--- a/chromium/cc/ipc/cc_param_traits_unittest.cc
+++ b/chromium/cc/ipc/cc_param_traits_unittest.cc
@@ -405,10 +405,10 @@ TEST_F(CCParamTraitsTest, AllQuads) {
pass_cmp->CopyFromAndAppendDrawQuad(texture_in);
TileDrawQuad* tile_in = pass_in->CreateAndAppendDrawQuad<TileDrawQuad>();
- tile_in->SetAll(shared_state3_in, arbitrary_rect2,
- arbitrary_rect1_inside_rect2, arbitrary_bool1,
- arbitrary_resourceid3, arbitrary_rectf1, arbitrary_size1,
- arbitrary_bool2, arbitrary_bool3, arbitrary_bool4);
+ tile_in->SetAll(
+ shared_state3_in, arbitrary_rect2, arbitrary_rect1_inside_rect2,
+ arbitrary_bool1, arbitrary_resourceid3, arbitrary_rectf1, arbitrary_size1,
+ arbitrary_bool2, arbitrary_bool3, arbitrary_bool4, arbitrary_bool5);
pass_cmp->CopyFromAndAppendDrawQuad(tile_in);
YUVVideoDrawQuad* yuvvideo_in =
diff --git a/chromium/cc/ipc/cc_serialization_perftest.cc b/chromium/cc/ipc/cc_serialization_perftest.cc
index d8741b8de02..7dc52dcff3f 100644
--- a/chromium/cc/ipc/cc_serialization_perftest.cc
+++ b/chromium/cc/ipc/cc_serialization_perftest.cc
@@ -14,7 +14,7 @@
#include "gpu/ipc/common/mailbox_struct_traits.h"
#include "gpu/ipc/common/sync_token_struct_traits.h"
#include "ipc/ipc_message.h"
-#include "mojo/common/time_struct_traits.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "mojo/public/cpp/bindings/message.h"
#include "services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h"
#include "services/viz/public/cpp/compositing/compositor_frame_struct_traits.h"
@@ -361,10 +361,11 @@ class CCSerializationPerfTest : public testing::Test {
arbitrary_blend_mode2, arbitrary_context_id2);
for (uint32_t j = 0; j < 6; ++j) {
auto* tile_in = pass_in->CreateAndAppendDrawQuad<viz::TileDrawQuad>();
- tile_in->SetAll(
- shared_state2_in, arbitrary_rect2, arbitrary_rect1_inside_rect2,
- arbitrary_bool1, arbitrary_resourceid3, arbitrary_rectf1,
- arbitrary_size1, arbitrary_bool2, arbitrary_bool3, arbitrary_bool4);
+ tile_in->SetAll(shared_state2_in, arbitrary_rect2,
+ arbitrary_rect1_inside_rect2, arbitrary_bool1,
+ arbitrary_resourceid3, arbitrary_rectf1,
+ arbitrary_size1, arbitrary_bool2, arbitrary_bool3,
+ arbitrary_bool4, arbitrary_bool5);
}
}
diff --git a/chromium/cc/layers/deadline_policy.cc b/chromium/cc/layers/deadline_policy.cc
index 91ba1912cc1..9c0f6fc8e24 100644
--- a/chromium/cc/layers/deadline_policy.cc
+++ b/chromium/cc/layers/deadline_policy.cc
@@ -4,6 +4,8 @@
#include "cc/layers/deadline_policy.h"
+#include <limits>
+
namespace cc {
// static
@@ -19,17 +21,18 @@ DeadlinePolicy DeadlinePolicy::UseDefaultDeadline() {
// static
DeadlinePolicy DeadlinePolicy::UseSpecifiedDeadline(
uint32_t deadline_in_frames) {
- return DeadlinePolicy(deadline_in_frames);
+ return DeadlinePolicy(Type::kUseSpecifiedDeadline, deadline_in_frames);
}
-DeadlinePolicy::DeadlinePolicy(Type policy_type)
- : policy_type_(policy_type), deadline_in_frames_(base::nullopt) {
- DCHECK_NE(Type::kUseSpecifiedDeadline, policy_type_);
+// static
+DeadlinePolicy DeadlinePolicy::UseInfiniteDeadline() {
+ return DeadlinePolicy(Type::kUseInfiniteDeadline,
+ std::numeric_limits<uint32_t>::max());
}
-DeadlinePolicy::DeadlinePolicy(uint32_t deadline_in_frames)
- : policy_type_(Type::kUseSpecifiedDeadline),
- deadline_in_frames_(deadline_in_frames) {}
+DeadlinePolicy::DeadlinePolicy(Type policy_type,
+ base::Optional<uint32_t> deadline_in_frames)
+ : policy_type_(policy_type), deadline_in_frames_(deadline_in_frames) {}
DeadlinePolicy::DeadlinePolicy(const DeadlinePolicy& other) = default;
diff --git a/chromium/cc/layers/deadline_policy.h b/chromium/cc/layers/deadline_policy.h
index a5dd80311fb..156c6df9432 100644
--- a/chromium/cc/layers/deadline_policy.h
+++ b/chromium/cc/layers/deadline_policy.h
@@ -18,7 +18,8 @@ class CC_EXPORT DeadlinePolicy {
enum Type {
kUseExistingDeadline,
kUseDefaultDeadline,
- kUseSpecifiedDeadline
+ kUseSpecifiedDeadline,
+ kUseInfiniteDeadline
};
static DeadlinePolicy UseExistingDeadline();
@@ -27,6 +28,8 @@ class CC_EXPORT DeadlinePolicy {
static DeadlinePolicy UseSpecifiedDeadline(uint32_t deadline_in_frames);
+ static DeadlinePolicy UseInfiniteDeadline();
+
DeadlinePolicy(const DeadlinePolicy& other);
DeadlinePolicy& operator=(const DeadlinePolicy& other) = default;
@@ -39,7 +42,8 @@ class CC_EXPORT DeadlinePolicy {
base::Optional<uint32_t> deadline_in_frames() const {
DCHECK(policy_type_ == Type::kUseDefaultDeadline ||
- policy_type_ == Type::kUseSpecifiedDeadline);
+ policy_type_ == Type::kUseSpecifiedDeadline ||
+ policy_type_ == Type::kUseInfiniteDeadline);
return deadline_in_frames_;
}
@@ -55,9 +59,9 @@ class CC_EXPORT DeadlinePolicy {
}
private:
- explicit DeadlinePolicy(Type policy_type);
-
- explicit DeadlinePolicy(uint32_t deadline_in_frames);
+ explicit DeadlinePolicy(
+ Type policy_type,
+ base::Optional<uint32_t> deadline_in_frames = base::nullopt);
Type policy_type_;
base::Optional<uint32_t> deadline_in_frames_;
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index b411caf3edf..8f2a21ea3fd 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -19,6 +19,7 @@
#include "cc/raster/scoped_gpu_raster.h"
#include "cc/resources/memory_history.h"
#include "cc/trees/frame_rate_counter.h"
+#include "cc/trees/layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
@@ -26,7 +27,7 @@
#include "components/viz/common/gpu/texture_allocation.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
-#include "components/viz/common/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/bitmap_allocation.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "skia/ext/platform_canvas.h"
@@ -117,6 +118,20 @@ class HudGpuBacking : public ResourcePool::GpuBacking {
GLuint texture_id;
};
+class HudSoftwareBacking : public ResourcePool::SoftwareBacking {
+ public:
+ ~HudSoftwareBacking() override {
+ layer_tree_frame_sink->DidDeleteSharedBitmap(shared_bitmap_id);
+ }
+
+ base::UnguessableToken SharedMemoryGuid() override {
+ return shared_memory->mapped_id();
+ }
+
+ LayerTreeFrameSink* layer_tree_frame_sink;
+ std::unique_ptr<base::SharedMemory> shared_memory;
+};
+
bool HeadsUpDisplayLayerImpl::WillDraw(
DrawMode draw_mode,
LayerTreeResourceProvider* resource_provider) {
@@ -155,6 +170,7 @@ void HeadsUpDisplayLayerImpl::AppendQuads(viz::RenderPass* render_pass,
void HeadsUpDisplayLayerImpl::UpdateHudTexture(
DrawMode draw_mode,
+ LayerTreeFrameSink* layer_tree_frame_sink,
LayerTreeResourceProvider* resource_provider,
bool gpu_raster,
const viz::RenderPassList& list) {
@@ -228,13 +244,22 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
}
} else {
DCHECK_EQ(draw_mode, DRAW_MODE_SOFTWARE);
- viz::SharedBitmapManager* shared_bitmap_manager =
- layer_tree_impl()->shared_bitmap_manager();
- DCHECK(shared_bitmap_manager);
- if (!pool_resource.shared_bitmap()) {
- pool_resource.set_shared_bitmap(
- shared_bitmap_manager->AllocateSharedBitmap(pool_resource.size()));
+ if (!pool_resource.software_backing()) {
+ auto backing = std::make_unique<HudSoftwareBacking>();
+ backing->layer_tree_frame_sink = layer_tree_frame_sink;
+ backing->shared_bitmap_id = viz::SharedBitmap::GenerateId();
+ backing->shared_memory = viz::bitmap_allocation::AllocateMappedBitmap(
+ pool_resource.size(), pool_resource.format());
+
+ mojo::ScopedSharedBufferHandle handle =
+ viz::bitmap_allocation::DuplicateAndCloseMappedBitmap(
+ backing->shared_memory.get(), pool_resource.size(),
+ pool_resource.format());
+ layer_tree_frame_sink->DidAllocateSharedBitmap(std::move(handle),
+ backing->shared_bitmap_id);
+
+ pool_resource.set_software_backing(std::move(backing));
}
}
@@ -253,8 +278,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
LayerTreeResourceProvider::ScopedSkSurface scoped_surface(
context_provider->GrContext(), backing->texture_id,
backing->texture_target, pool_resource.size(), pool_resource.format(),
- false /* use_distance_field_text */, false /* can_use_lcd_text */,
- 0 /* msaa_sample_count */);
+ false /* can_use_lcd_text */, 0 /* msaa_sample_count */);
SkSurface* surface = scoped_surface.surface();
if (!surface) {
pool_->ReleaseResource(std::move(pool_resource));
@@ -298,12 +322,14 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
// memory bitmap, wrapped in an SkSurface, that can be shared to the display
// compositor.
DCHECK_EQ(draw_mode, DRAW_MODE_SOFTWARE);
- DCHECK(pool_resource.shared_bitmap());
+ DCHECK(pool_resource.software_backing());
SkImageInfo info = SkImageInfo::MakeN32Premul(
pool_resource.size().width(), pool_resource.size().height());
+ auto* backing =
+ static_cast<HudSoftwareBacking*>(pool_resource.software_backing());
sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(
- info, pool_resource.shared_bitmap()->pixels(), info.minRowBytes());
+ info, backing->shared_memory->memory(), info.minRowBytes());
DrawHudContents(surface->getCanvas());
}
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h
index 5994907193e..b6f5070ddd3 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.h
+++ b/chromium/cc/layers/heads_up_display_layer_impl.h
@@ -26,6 +26,7 @@ struct SkRect;
namespace cc {
class FrameRateCounter;
+class LayerTreeFrameSink;
class LayerTreeResourceProvider;
class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
@@ -44,6 +45,7 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
void AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
void UpdateHudTexture(DrawMode draw_mode,
+ LayerTreeFrameSink* frame_sink,
LayerTreeResourceProvider* 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 375b88012c5..6397ea81bb0 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
@@ -17,6 +17,7 @@ namespace cc {
namespace {
void CheckDrawLayer(HeadsUpDisplayLayerImpl* layer,
+ LayerTreeFrameSink* frame_sink,
LayerTreeResourceProvider* resource_provider,
viz::ContextProvider* context_provider,
DrawMode draw_mode) {
@@ -27,8 +28,8 @@ void CheckDrawLayer(HeadsUpDisplayLayerImpl* layer,
layer->AppendQuads(render_pass.get(), &data);
viz::RenderPassList pass_list;
pass_list.push_back(std::move(render_pass));
- layer->UpdateHudTexture(draw_mode, resource_provider, context_provider,
- pass_list);
+ layer->UpdateHudTexture(draw_mode, frame_sink, resource_provider,
+ context_provider, pass_list);
if (will_draw)
layer->DidDraw(resource_provider);
@@ -57,14 +58,16 @@ TEST(HeadsUpDisplayLayerImplTest, ResourcelessSoftwareDrawAfterResourceLoss) {
host_impl.pending_tree()->BuildLayerListAndPropertyTreesForTesting();
// Check regular hardware draw is ok.
- CheckDrawLayer(layer, host_impl.resource_provider(),
+ CheckDrawLayer(layer, host_impl.layer_tree_frame_sink(),
+ host_impl.resource_provider(),
layer_tree_frame_sink->context_provider(), DRAW_MODE_HARDWARE);
// Simulate a resource loss on transitioning to resourceless software mode.
layer->ReleaseResources();
// Should skip resourceless software draw and not crash in UpdateHudTexture.
- CheckDrawLayer(layer, host_impl.resource_provider(),
+ CheckDrawLayer(layer, host_impl.layer_tree_frame_sink(),
+ host_impl.resource_provider(),
layer_tree_frame_sink->context_provider(),
DRAW_MODE_RESOURCELESS_SOFTWARE);
}
@@ -88,7 +91,8 @@ TEST(HeadsUpDisplayLayerImplTest, CPUAndGPURasterCanvas) {
host_impl.pending_tree()->BuildLayerListAndPropertyTreesForTesting();
// Check Ganesh canvas drawing is ok.
- CheckDrawLayer(layer, host_impl.resource_provider(),
+ CheckDrawLayer(layer, host_impl.layer_tree_frame_sink(),
+ host_impl.resource_provider(),
layer_tree_frame_sink->context_provider(), DRAW_MODE_HARDWARE);
host_impl.ReleaseLayerTreeFrameSink();
@@ -96,8 +100,8 @@ TEST(HeadsUpDisplayLayerImplTest, CPUAndGPURasterCanvas) {
host_impl.InitializeRenderer(layer_tree_frame_sink.get());
// Check SW canvas drawing is ok.
- CheckDrawLayer(layer, host_impl.resource_provider(), nullptr,
- DRAW_MODE_SOFTWARE);
+ CheckDrawLayer(layer, host_impl.layer_tree_frame_sink(),
+ host_impl.resource_provider(), nullptr, DRAW_MODE_SOFTWARE);
}
} // namespace
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index 54123327c01..f8f478a6486 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -65,7 +65,7 @@ Layer::Inputs::Inputs(int layer_id)
has_will_change_transform_hint(false),
trilinear_filtering(false),
hide_layer_and_subtree(false),
- client(nullptr),
+ client_rawptr(nullptr),
overscroll_behavior(OverscrollBehavior::kOverscrollBehaviorTypeAuto) {}
Layer::Inputs::~Inputs() = default;
@@ -290,7 +290,9 @@ void Layer::SetBounds(const gfx::Size& size) {
if (!layer_tree_host_)
return;
- if (masks_to_bounds()) {
+ // Both bounds clipping and mask clipping can result in new areas of subtrees
+ // being exposed on a bounds change. Ensure the damaged areas are updated.
+ if (masks_to_bounds() || inputs_.mask_layer.get()) {
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
}
@@ -1160,6 +1162,13 @@ void Layer::SetStickyPositionConstraint(
SetNeedsCommit();
}
+void Layer::SetLayerClient(base::WeakPtr<LayerClient> client) {
+ inputs_.client = std::move(client);
+ // Both binds the weak_ptr to the main thread and stores a rawptr for access
+ // during commit.
+ inputs_.client_rawptr = client.get();
+}
+
bool Layer::IsSnapped() {
return scrollable();
}
@@ -1314,8 +1323,15 @@ bool Layer::HasNonAAPaint() const {
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
Layer::TakeDebugInfo() {
- if (inputs_.client)
- return inputs_.client->TakeDebugInfo(this);
+ // TakeDebugInfo is called from the compositor thread while the main thread is
+ // blocked so we use the raw client pointer as we can't check whether the
+ // reference is safe on the weak pointer.
+ // TODO(flackr): Remove client_rawptr and figure out if we can take the debug
+ // info from the main thread and store it on inputs before doing the commit or
+ // make a WeakPtr which understands the commit and allows checked access from
+ // the compositor thread. https://crbug.com/826455
+ if (inputs_.client_rawptr)
+ return inputs_.client_rawptr->TakeDebugInfo(this);
else
return nullptr;
}
@@ -1341,7 +1357,7 @@ void Layer::SetMayContainVideo(bool yes) {
void Layer::SetScrollbarsHiddenFromImplSide(bool hidden) {
if (inputs_.client)
- inputs_.client->didChangeScrollbarsHidden(hidden);
+ inputs_.client->didChangeScrollbarsHiddenIfOverlay(hidden);
}
// On<Property>Animated is called due to an ongoing accelerated animation.
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index ad25a15d577..eca81a044cf 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -335,7 +335,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
TakeDebugInfo();
virtual void didUpdateMainThreadScrollingReasons();
- void SetLayerClient(LayerClient* client) { inputs_.client = client; }
+ void SetLayerClient(base::WeakPtr<LayerClient> client);
virtual bool IsSnapped();
@@ -627,7 +627,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
bool hide_layer_and_subtree : 1;
// The following elements can not and are not serialized.
- LayerClient* client;
+ base::WeakPtr<LayerClient> client;
+ // During commit, the main thread is blocked on the compositor thread, so
+ // we use the raw pointer to the LayerClient.
+ LayerClient* client_rawptr;
+
base::Callback<void(const gfx::ScrollOffset&, const ElementId&)>
did_scroll_callback;
std::vector<std::unique_ptr<viz::CopyOutputRequest>> copy_requests;
diff --git a/chromium/cc/layers/layer_client.h b/chromium/cc/layers/layer_client.h
index 85c97722c0d..10ded49b5a5 100644
--- a/chromium/cc/layers/layer_client.h
+++ b/chromium/cc/layers/layer_client.h
@@ -31,7 +31,7 @@ class CC_EXPORT LayerClient {
virtual std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
TakeDebugInfo(Layer* layer) = 0;
virtual void didUpdateMainThreadScrollingReasons() = 0;
- virtual void didChangeScrollbarsHidden(bool) = 0;
+ virtual void didChangeScrollbarsHiddenIfOverlay(bool) = 0;
protected:
virtual ~LayerClient() {}
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index 6e1dfe9bf90..89b4bdf6a80 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -11,7 +11,6 @@
#include <utility>
#include "base/json/json_reader.h"
-#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
@@ -494,10 +493,6 @@ void LayerImpl::ResetChangeTracking() {
damage_rect_.SetRect(0, 0, 0, 0);
}
-bool LayerImpl::has_copy_requests_in_target_subtree() {
- return GetEffectTree().Node(effect_tree_index())->subtree_has_copy_request;
-}
-
bool LayerImpl::IsActive() const {
return layer_tree_impl_->IsActiveTree();
}
@@ -638,10 +633,6 @@ float LayerImpl::Opacity() const {
return 1.f;
}
-const gfx::Transform& LayerImpl::Transform() const {
- return GetTransformTree().Node(transform_tree_index())->local;
-}
-
void LayerImpl::SetElementId(ElementId element_id) {
if (element_id == element_id_)
return;
@@ -947,4 +938,8 @@ void LayerImpl::EnsureValidPropertyTreeIndices() const {
DCHECK(GetScrollTree().Node(scroll_tree_index()));
}
+bool LayerImpl::is_surface_layer() const {
+ return false;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h
index 01032faf6e0..6eb7daabac1 100644
--- a/chromium/cc/layers/layer_impl.h
+++ b/chromium/cc/layers/layer_impl.h
@@ -86,7 +86,8 @@ class CC_EXPORT LayerImpl {
int id() const { return layer_id_; }
- // Interactions with attached animations.
+ // Whether this layer is on the active tree, return false if it's on the
+ // pending tree.
bool IsActive() const;
void SetHasTransformNode(bool val) { has_transform_node_ = val; }
@@ -123,8 +124,6 @@ class CC_EXPORT LayerImpl {
bool is_clipped() const { return draw_properties_.is_clipped; }
- void UpdatePropertyTreeScrollOffset();
-
LayerTreeImpl* layer_tree_impl() const { return layer_tree_impl_; }
void PopulateSharedQuadState(viz::SharedQuadState* state,
@@ -196,7 +195,6 @@ class CC_EXPORT LayerImpl {
bool contents_opaque() const { return contents_opaque_; }
float Opacity() const;
- const gfx::Transform& Transform() const;
// Stable identifier for clients. See comment in cc/trees/element_id.h.
void SetElementId(ElementId element_id);
@@ -419,8 +417,6 @@ class CC_EXPORT LayerImpl {
virtual gfx::Rect GetEnclosingRectInTargetSpace() const;
- bool has_copy_requests_in_target_subtree();
-
void UpdatePropertyTreeForAnimationIfNeeded(ElementId element_id);
float GetIdealContentsScale() const;
@@ -450,6 +446,9 @@ class CC_EXPORT LayerImpl {
void EnsureValidPropertyTreeIndices() const;
+ // TODO(sunxd): Remove this function and replace it with visitor pattern.
+ virtual bool is_surface_layer() const;
+
protected:
LayerImpl(LayerTreeImpl* layer_impl,
int id,
@@ -533,7 +532,6 @@ class CC_EXPORT LayerImpl {
gfx::PointF position_;
- gfx::Rect clip_rect_in_target_space_;
int transform_tree_index_;
int effect_tree_index_;
int clip_tree_index_;
diff --git a/chromium/cc/layers/layer_impl_test_properties.h b/chromium/cc/layers/layer_impl_test_properties.h
index f2cace080cd..0171895c604 100644
--- a/chromium/cc/layers/layer_impl_test_properties.h
+++ b/chromium/cc/layers/layer_impl_test_properties.h
@@ -8,7 +8,6 @@
#include <set>
#include <vector>
-#include "base/memory/ptr_util.h"
#include "cc/input/overscroll_behavior.h"
#include "cc/input/scroll_snap_data.h"
#include "cc/layers/layer_collections.h"
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index 53e58744d20..3c898c8c12d 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
@@ -255,6 +254,13 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
std::unique_ptr<LayerImpl> dummy_layer1_impl =
LayerImpl::Create(host_impl_.active_tree(), dummy_layer1->id());
+ // 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(
@@ -264,6 +270,12 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
grand_child->PushPropertiesTo(grand_child_impl.get());
dummy_layer1->PushPropertiesTo(dummy_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));
+
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetMasksToBounds(true));
EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
@@ -322,7 +334,7 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
// Should be a different size than previous call, to ensure it marks tree
// changed.
- gfx::Size arbitrary_size = gfx::Size(111, 222);
+ 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));
diff --git a/chromium/cc/layers/nine_patch_generator.h b/chromium/cc/layers/nine_patch_generator.h
index bb0cd34fd44..f413e4f5d9c 100644
--- a/chromium/cc/layers/nine_patch_generator.h
+++ b/chromium/cc/layers/nine_patch_generator.h
@@ -9,7 +9,6 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "cc/cc_export.h"
#include "cc/resources/ui_resource_client.h"
#include "ui/gfx/geometry/rect.h"
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
index f60f6cd77f2..acb02addf13 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
@@ -90,6 +90,11 @@ void PaintedOverlayScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
scrollbar_layer->SetAperture(gfx::Rect());
scrollbar_layer->set_thumb_ui_resource_id(0);
}
+
+ if (track_resource_.get())
+ scrollbar_layer->set_track_ui_resource_id(track_resource_->id());
+ else
+ scrollbar_layer->set_track_ui_resource_id(0);
}
ScrollbarLayerInterface* PaintedOverlayScrollbarLayer::ToScrollbarLayer() {
@@ -99,8 +104,10 @@ ScrollbarLayerInterface* PaintedOverlayScrollbarLayer::ToScrollbarLayer() {
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.
- if (host != layer_tree_host())
- thumb_resource_ = nullptr;
+ if (host != layer_tree_host()) {
+ thumb_resource_.reset();
+ track_resource_.reset();
+ }
Layer::SetLayerTreeHost(host);
}
@@ -121,6 +128,7 @@ bool PaintedOverlayScrollbarLayer::Update() {
updated |= UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_);
updated |= UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_);
updated |= PaintThumbIfNeeded();
+ updated |= PaintTickmarks();
return updated;
}
@@ -159,4 +167,43 @@ bool PaintedOverlayScrollbarLayer::PaintThumbIfNeeded() {
return true;
}
+bool PaintedOverlayScrollbarLayer::PaintTickmarks() {
+ if (!scrollbar_->HasTickmarks()) {
+ if (!track_resource_) {
+ return false;
+ } else {
+ // Remove previous tickmarks.
+ track_resource_.reset();
+ SetNeedsPushProperties();
+ return true;
+ }
+ }
+
+ gfx::Rect paint_rect = gfx::Rect(gfx::Point(), track_rect_.size());
+
+ DCHECK(!paint_rect.size().IsEmpty());
+
+ SkBitmap skbitmap;
+ skbitmap.allocN32Pixels(paint_rect.width(), paint_rect.height());
+ SkiaPaintCanvas canvas(skbitmap);
+
+ SkRect content_skrect = RectToSkRect(paint_rect);
+ PaintFlags flags;
+ flags.setAntiAlias(false);
+ flags.setBlendMode(SkBlendMode::kClear);
+ canvas.drawRect(content_skrect, flags);
+ canvas.clipRect(content_skrect);
+
+ scrollbar_->PaintPart(&canvas, TICKMARKS, paint_rect);
+ // Make sure that the pixels are no longer mutable to unavoid unnecessary
+ // allocation and copying.
+ skbitmap.setImmutable();
+
+ track_resource_ = ScopedUIResource::Create(
+ layer_tree_host()->GetUIResourceManager(), UIResourceBitmap(skbitmap));
+
+ SetNeedsPushProperties();
+ return true;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.h b/chromium/cc/layers/painted_overlay_scrollbar_layer.h
index eb5a749fdde..7f4c555d6ce 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer.h
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.h
@@ -53,6 +53,7 @@ class CC_EXPORT PaintedOverlayScrollbarLayer : public ScrollbarLayerInterface,
}
bool PaintThumbIfNeeded();
+ bool PaintTickmarks();
std::unique_ptr<Scrollbar> scrollbar_;
ElementId scroll_element_id_;
@@ -65,6 +66,7 @@ class CC_EXPORT PaintedOverlayScrollbarLayer : public ScrollbarLayerInterface,
gfx::Rect aperture_;
std::unique_ptr<ScopedUIResource> thumb_resource_;
+ std::unique_ptr<ScopedUIResource> track_resource_;
DISALLOW_COPY_AND_ASSIGN(PaintedOverlayScrollbarLayer);
};
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
index cd24f21c667..4f5a61eb060 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
@@ -3,7 +3,10 @@
// found in the LICENSE file.
#include "cc/layers/painted_overlay_scrollbar_layer_impl.h"
+
#include "cc/trees/layer_tree_impl.h"
+#include "components/viz/common/quads/solid_color_draw_quad.h"
+#include "components/viz/common/quads/texture_draw_quad.h"
namespace cc {
@@ -27,6 +30,7 @@ PaintedOverlayScrollbarLayerImpl::PaintedOverlayScrollbarLayerImpl(
is_left_side_vertical_scrollbar,
true),
thumb_ui_resource_id_(0),
+ track_ui_resource_id_(0),
thumb_thickness_(0),
thumb_length_(0),
track_start_(0),
@@ -55,6 +59,7 @@ void PaintedOverlayScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
scrollbar_layer->SetAperture(aperture_);
scrollbar_layer->set_thumb_ui_resource_id(thumb_ui_resource_id_);
+ scrollbar_layer->set_track_ui_resource_id(track_ui_resource_id_);
}
bool PaintedOverlayScrollbarLayerImpl::WillDraw(
@@ -67,11 +72,19 @@ bool PaintedOverlayScrollbarLayerImpl::WillDraw(
void PaintedOverlayScrollbarLayerImpl::AppendQuads(
viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) {
+ viz::SharedQuadState* shared_quad_state =
+ render_pass->CreateAndAppendSharedQuadState();
+ AppendThumbQuads(render_pass, append_quads_data, shared_quad_state);
+ AppendTrackQuads(render_pass, append_quads_data, shared_quad_state);
+}
+
+void PaintedOverlayScrollbarLayerImpl::AppendThumbQuads(
+ viz::RenderPass* render_pass,
+ AppendQuadsData* append_quads_data,
+ viz::SharedQuadState* shared_quad_state) {
if (aperture_.IsEmpty())
return;
- viz::SharedQuadState* shared_quad_state =
- render_pass->CreateAndAppendSharedQuadState();
bool is_resource =
thumb_ui_resource_id_ &&
layer_tree_impl()->ResourceIdForUIResource(thumb_ui_resource_id_);
@@ -118,6 +131,41 @@ void PaintedOverlayScrollbarLayerImpl::AppendQuads(
shared_quad_state, patches);
}
+void PaintedOverlayScrollbarLayerImpl::AppendTrackQuads(
+ viz::RenderPass* render_pass,
+ AppendQuadsData* append_quads_data,
+ viz::SharedQuadState* shared_quad_state) {
+ viz::ResourceId track_resource_id =
+ layer_tree_impl()->ResourceIdForUIResource(track_ui_resource_id_);
+ if (!track_resource_id)
+ return;
+
+ bool nearest_neighbor = false;
+
+ gfx::Rect track_quad_rect(bounds());
+ gfx::Rect scaled_track_quad_rect(bounds());
+ gfx::Rect visible_track_quad_rect =
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ track_quad_rect);
+ gfx::Rect scaled_visible_track_quad_rect =
+ gfx::ScaleToEnclosingRect(visible_track_quad_rect, 1.f);
+
+ bool needs_blending = !contents_opaque();
+ bool premultipled_alpha = true;
+ bool flipped = false;
+ gfx::PointF uv_top_left(0.f, 0.f);
+ gfx::PointF uv_bottom_right(1.f, 1.f);
+ float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ viz::TextureDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
+ quad->SetNew(shared_quad_state, scaled_track_quad_rect,
+ scaled_visible_track_quad_rect, needs_blending,
+ track_resource_id, premultipled_alpha, uv_top_left,
+ uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped,
+ nearest_neighbor, false);
+ ValidateQuadResources(quad);
+}
+
void PaintedOverlayScrollbarLayerImpl::SetThumbThickness(int thumb_thickness) {
if (thumb_thickness_ == thumb_thickness)
return;
@@ -184,4 +232,8 @@ const char* PaintedOverlayScrollbarLayerImpl::LayerTypeAsString() const {
return "cc::PaintedOverlayScrollbarLayerImpl";
}
+bool PaintedOverlayScrollbarLayerImpl::HasFindInPageTickmarks() const {
+ return track_ui_resource_id_ != 0;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h
index 104287b1995..ca436bd40b9 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.h
@@ -47,6 +47,12 @@ class CC_EXPORT PaintedOverlayScrollbarLayerImpl
thumb_ui_resource_id_ = uid;
}
+ void set_track_ui_resource_id(UIResourceId uid) {
+ track_ui_resource_id_ = uid;
+ }
+
+ bool HasFindInPageTickmarks() const override;
+
protected:
PaintedOverlayScrollbarLayerImpl(LayerTreeImpl* tree_impl,
int id,
@@ -63,7 +69,16 @@ class CC_EXPORT PaintedOverlayScrollbarLayerImpl
private:
const char* LayerTypeAsString() const override;
+ void AppendThumbQuads(viz::RenderPass* render_pass,
+ AppendQuadsData* append_quads_data,
+ viz::SharedQuadState* shared_quad_state);
+
+ void AppendTrackQuads(viz::RenderPass* render_pass,
+ AppendQuadsData* append_quads_data,
+ viz::SharedQuadState* shared_quad_state);
+
UIResourceId thumb_ui_resource_id_;
+ UIResourceId track_ui_resource_id_;
int thumb_thickness_;
int thumb_length_;
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc
new file mode 100644
index 00000000000..c510444b898
--- /dev/null
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc
@@ -0,0 +1,88 @@
+// 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/layers/painted_overlay_scrollbar_layer.h"
+
+#include "cc/animation/animation_host.h"
+#include "cc/test/fake_layer_tree_host.h"
+#include "cc/test/fake_layer_tree_host_client.h"
+#include "cc/test/fake_scrollbar.h"
+#include "cc/test/test_task_graph_runner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+
+namespace {
+
+class MockScrollbar : public FakeScrollbar {
+ public:
+ MockScrollbar() : FakeScrollbar(true, true, true) {}
+
+ void PaintPart(PaintCanvas* canvas,
+ ScrollbarPart part,
+ const gfx::Rect& content_rect) override {
+ if (part == TICKMARKS)
+ paint_tickmarks_called_ = true;
+ }
+
+ bool UsesNinePatchThumbResource() const override { return true; }
+
+ gfx::Size NinePatchThumbCanvasSize() const override {
+ return gfx::Size(10, 10);
+ }
+
+ bool PaintTickmarksCalled() { return paint_tickmarks_called_; }
+
+ void SetPaintTickmarksCalled(bool called) {
+ paint_tickmarks_called_ = called;
+ }
+
+ private:
+ bool paint_tickmarks_called_ = false;
+};
+
+TEST(PaintedOverlayScrollbarLayerTest, PaintTickmarks) {
+ FakeLayerTreeHostClient fake_client_;
+ TestTaskGraphRunner task_graph_runner_;
+
+ auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN);
+ auto layer_tree_host = FakeLayerTreeHost::Create(
+ &fake_client_, &task_graph_runner_, animation_host.get());
+
+ MockScrollbar* scrollbar = new MockScrollbar();
+ scrollbar->set_has_tickmarks(false);
+
+ scoped_refptr<PaintedOverlayScrollbarLayer> scrollbar_layer =
+ PaintedOverlayScrollbarLayer::Create(
+ std::unique_ptr<Scrollbar>(scrollbar));
+
+ scrollbar_layer->SetIsDrawable(true);
+ scrollbar_layer->SetBounds(gfx::Size(100, 100));
+
+ layer_tree_host->SetRootLayer(scrollbar_layer);
+ EXPECT_EQ(scrollbar_layer->GetLayerTreeHostForTesting(),
+ layer_tree_host.get());
+
+ // Request no paint when initialization.
+ scrollbar_layer->Update();
+ EXPECT_FALSE(scrollbar->PaintTickmarksCalled());
+
+ // The next update will paint nothing because still no tickmarks applied.
+ scrollbar_layer->Update();
+ EXPECT_FALSE(scrollbar->PaintTickmarksCalled());
+
+ // Enable the tickmarks.
+ scrollbar->set_has_tickmarks(true);
+ scrollbar_layer->Update();
+ EXPECT_TRUE(scrollbar->PaintTickmarksCalled());
+ scrollbar->SetPaintTickmarksCalled(false);
+
+ // Disable the tickmarks. No paint.
+ scrollbar->set_has_tickmarks(false);
+ scrollbar_layer->Update();
+ EXPECT_FALSE(scrollbar->PaintTickmarksCalled());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index bc1573be04f..e52dfccf2c4 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -106,7 +106,8 @@ gfx::Size ApplyDsfAdjustment(gfx::Size device_pixels_size, float dsf) {
// don't need any settings. The current approach uses 4 tiles to cover the
// viewport vertically.
gfx::Size CalculateGpuTileSize(const gfx::Size& base_tile_size,
- const gfx::Size& content_bounds) {
+ const gfx::Size& content_bounds,
+ const gfx::Size& max_tile_size) {
int tile_width = base_tile_size.width();
// Increase the height proportionally as the width decreases, and pad by our
@@ -130,6 +131,11 @@ gfx::Size CalculateGpuTileSize(const gfx::Size& base_tile_size,
tile_height = std::max(tile_height, kMinHeightForGpuRasteredTile);
+ if (!max_tile_size.IsEmpty()) {
+ tile_width = std::min(tile_width, max_tile_size.width());
+ tile_height = std::min(tile_height, max_tile_size.height());
+ }
+
return gfx::Size(tile_width, tile_height);
}
@@ -470,7 +476,7 @@ void PictureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
offset_visible_geometry_rect, needs_blending,
draw_info.resource_id_for_export(), texture_rect,
draw_info.resource_size(), draw_info.contents_swizzled(),
- nearest_neighbor_,
+ draw_info.is_premultiplied(), nearest_neighbor_,
!layer_tree_impl()->settings().enable_edge_anti_aliasing);
ValidateQuadResources(quad);
has_draw_quad = true;
@@ -940,6 +946,9 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
int default_tile_width = 0;
int default_tile_height = 0;
if (layer_tree_impl()->use_gpu_rasterization()) {
+ gfx::Size max_tile_size =
+ layer_tree_impl()->settings().max_gpu_raster_tile_size;
+
// Calculate |base_tile_size based| on |gpu_raster_max_texture_size_|,
// adjusting for ceil operations that may occur due to DSF.
gfx::Size base_tile_size = ApplyDsfAdjustment(
@@ -948,14 +957,15 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
// Set our initial size assuming a |base_tile_size| equal to our
// |viewport_size|.
gfx::Size default_tile_size =
- CalculateGpuTileSize(base_tile_size, content_bounds);
+ CalculateGpuTileSize(base_tile_size, content_bounds, max_tile_size);
// Use half-width GPU tiles when the content_width is greater than our
// calculated tile size.
if (content_bounds.width() > default_tile_size.width()) {
// Divide width by 2 and round up.
base_tile_size.set_width((base_tile_size.width() + 1) / 2);
- default_tile_size = CalculateGpuTileSize(base_tile_size, content_bounds);
+ default_tile_size =
+ CalculateGpuTileSize(base_tile_size, content_bounds, max_tile_size);
}
default_tile_width = default_tile_size.width();
@@ -1504,7 +1514,8 @@ std::unique_ptr<PictureLayerTilingSet>
PictureLayerImpl::CreatePictureLayerTilingSet() {
const LayerTreeSettings& settings = layer_tree_impl()->settings();
return PictureLayerTilingSet::Create(
- GetTree(), this, settings.tiling_interest_area_padding,
+ IsActive() ? ACTIVE_TREE : PENDING_TREE, this,
+ settings.tiling_interest_area_padding,
layer_tree_impl()->use_gpu_rasterization()
? settings.gpu_rasterization_skewport_target_time_in_seconds
: settings.skewport_target_time_in_seconds,
@@ -1624,10 +1635,6 @@ void PictureLayerImpl::RunMicroBenchmark(MicroBenchmarkImpl* benchmark) {
benchmark->RunOnLayer(this);
}
-WhichTree PictureLayerImpl::GetTree() const {
- return layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
-}
-
bool PictureLayerImpl::IsOnActiveOrPendingTree() const {
return !layer_tree_impl()->IsRecycleTree();
}
@@ -1679,9 +1686,6 @@ void PictureLayerImpl::RegisterAnimatedImages() {
return;
auto* controller = layer_tree_impl()->image_animation_controller();
- if (!controller)
- return;
-
const auto& metadata = raster_source_->GetDisplayItemList()
->discardable_image_map()
.animated_images_metadata();
@@ -1698,9 +1702,6 @@ void PictureLayerImpl::UnregisterAnimatedImages() {
return;
auto* controller = layer_tree_impl()->image_animation_controller();
- if (!controller)
- return;
-
const auto& metadata = raster_source_->GetDisplayItemList()
->discardable_image_map()
.animated_images_metadata();
diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h
index 319300cf130..d0348102464 100644
--- a/chromium/cc/layers/picture_layer_impl.h
+++ b/chromium/cc/layers/picture_layer_impl.h
@@ -78,7 +78,6 @@ class CC_EXPORT PictureLayerImpl
bool UpdateTiles();
// Returns true if the LCD state changed.
bool UpdateCanUseLCDTextAfterCommit();
- WhichTree GetTree() const;
// Mask-related functions.
void GetContentsResourceId(viz::ResourceId* resource_id,
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index dfccb52a619..38e0a3ac30a 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -83,7 +83,6 @@ class PictureLayerImplTest : public TestLayerTreeHostBase {
settings.commit_to_active_tree = false;
settings.layer_transforms_should_scale_layer_contents = true;
settings.create_low_res_tiling = true;
- settings.enable_image_animations = true;
return settings;
}
diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc
index baa05d6ae46..1c92c7e9785 100644
--- a/chromium/cc/layers/picture_layer_unittest.cc
+++ b/chromium/cc/layers/picture_layer_unittest.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/animation/animation_host.h"
#include "cc/layers/append_quads_data.h"
diff --git a/chromium/cc/layers/recording_source.cc b/chromium/cc/layers/recording_source.cc
index 80648d3850b..66c44cc06a5 100644
--- a/chromium/cc/layers/recording_source.cc
+++ b/chromium/cc/layers/recording_source.cc
@@ -141,11 +141,11 @@ void RecordingSource::DetermineIfSolidColor() {
is_solid_color_ = false;
solid_color_ = SK_ColorTRANSPARENT;
- if (display_list_->op_count() > kMaxOpsToAnalyzeForLayer)
+ if (display_list_->TotalOpCount() > kMaxOpsToAnalyzeForLayer)
return;
TRACE_EVENT1("cc", "RecordingSource::DetermineIfSolidColor", "opcount",
- display_list_->op_count());
+ display_list_->TotalOpCount());
is_solid_color_ = display_list_->GetColorIfSolidInRect(
gfx::ScaleToRoundedRect(gfx::Rect(GetSize()), recording_scale_factor_),
&solid_color_, kMaxOpsToAnalyzeForLayer);
diff --git a/chromium/cc/layers/recording_source_unittest.cc b/chromium/cc/layers/recording_source_unittest.cc
index 82c424ff8ef..15b5249fc10 100644
--- a/chromium/cc/layers/recording_source_unittest.cc
+++ b/chromium/cc/layers/recording_source_unittest.cc
@@ -4,7 +4,6 @@
#include <vector>
-#include "base/memory/ptr_util.h"
#include "cc/base/region.h"
#include "cc/raster/raster_source.h"
#include "cc/test/fake_content_layer_client.h"
diff --git a/chromium/cc/layers/render_surface_unittest.cc b/chromium/cc/layers/render_surface_unittest.cc
index 8385acee844..714ddd49916 100644
--- a/chromium/cc/layers/render_surface_unittest.cc
+++ b/chromium/cc/layers/render_surface_unittest.cc
@@ -68,7 +68,7 @@ class FakePictureLayerImplForRenderSurfaceTest : public FakePictureLayerImpl {
for (const auto& rect : quad_rects_) {
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::TileDrawQuad>();
quad->SetNew(shared_quad_state, rect, rect, needs_blending, 0,
- gfx::RectF(rect), bounds(), false, false, false);
+ gfx::RectF(rect), bounds(), false, false, false, false);
}
}
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.cc b/chromium/cc/layers/scrollbar_layer_impl_base.cc
index 1758c6f154a..6a0f9eb613e 100644
--- a/chromium/cc/layers/scrollbar_layer_impl_base.cc
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.cc
@@ -270,4 +270,8 @@ ScrollbarLayerImplBase::GetScrollbarAnimator() const {
return layer_tree_impl()->settings().scrollbar_animator;
}
+bool ScrollbarLayerImplBase::HasFindInPageTickmarks() const {
+ return false;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.h b/chromium/cc/layers/scrollbar_layer_impl_base.h
index df9b3d1eaa1..8c38e0e1584 100644
--- a/chromium/cc/layers/scrollbar_layer_impl_base.h
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.h
@@ -64,6 +64,10 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
virtual LayerTreeSettings::ScrollbarAnimator GetScrollbarAnimator() const;
+ // Only PaintedOverlayScrollbar(Aura Overlay Scrollbar) need to know
+ // tickmarks's state.
+ virtual bool HasFindInPageTickmarks() const;
+
protected:
ScrollbarLayerImplBase(LayerTreeImpl* tree_impl,
int id,
diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc
index 892bbd71bb7..94935c08f07 100644
--- a/chromium/cc/layers/scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/scrollbar_layer_unittest.cc
@@ -6,7 +6,6 @@
#include <unordered_map>
-#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/animation/animation_host.h"
#include "cc/input/scrollbar_animation_controller.h"
diff --git a/chromium/cc/layers/surface_layer.cc b/chromium/cc/layers/surface_layer.cc
index 2aae0de35f2..8a123ca8587 100644
--- a/chromium/cc/layers/surface_layer.cc
+++ b/chromium/cc/layers/surface_layer.cc
@@ -7,7 +7,6 @@
#include <stdint.h>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "cc/layers/surface_layer_impl.h"
#include "cc/trees/layer_tree_host.h"
@@ -60,6 +59,13 @@ void SurfaceLayer::SetStretchContentToFillBounds(
SetNeedsPushProperties();
}
+void SurfaceLayer::SetHitTestable(bool hit_testable) {
+ if (hit_testable_ == hit_testable)
+ return;
+ hit_testable_ = hit_testable;
+ SetNeedsPushProperties();
+}
+
std::unique_ptr<LayerImpl> SurfaceLayer::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
return SurfaceLayerImpl::Create(tree_impl, id());
@@ -94,6 +100,7 @@ void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) {
deadline_in_frames_ = 0u;
layer_impl->SetFallbackSurfaceId(fallback_surface_id_);
layer_impl->SetStretchContentToFillBounds(stretch_content_to_fill_bounds_);
+ layer_impl->SetHitTestable(hit_testable_);
}
} // namespace cc
diff --git a/chromium/cc/layers/surface_layer.h b/chromium/cc/layers/surface_layer.h
index 2dbe358ab02..3ed0b9ad140 100644
--- a/chromium/cc/layers/surface_layer.h
+++ b/chromium/cc/layers/surface_layer.h
@@ -28,6 +28,12 @@ class CC_EXPORT SurfaceLayer : public Layer {
// When stretch_content_to_fill_bounds is true, the scale of the embedded
// surface is ignored and the content will be stretched to fill the bounds.
void SetStretchContentToFillBounds(bool stretch_content_to_fill_bounds);
+ bool stretch_content_to_fill_bounds() const {
+ return stretch_content_to_fill_bounds_;
+ }
+
+ void SetHitTestable(bool hit_testable);
+ bool hit_testable() const { return hit_testable_; }
// Layer overrides.
std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -58,6 +64,7 @@ class CC_EXPORT SurfaceLayer : public Layer {
base::Optional<uint32_t> deadline_in_frames_ = 0u;
bool stretch_content_to_fill_bounds_ = false;
+ bool hit_testable_ = false;
DISALLOW_COPY_AND_ASSIGN(SurfaceLayer);
};
diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc
index e42794a74c4..d90e233bfd3 100644
--- a/chromium/cc/layers/surface_layer_impl.cc
+++ b/chromium/cc/layers/surface_layer_impl.cc
@@ -54,6 +54,14 @@ void SurfaceLayerImpl::SetStretchContentToFillBounds(bool stretch_content) {
NoteLayerPropertyChanged();
}
+void SurfaceLayerImpl::SetHitTestable(bool hit_testable) {
+ if (hit_testable_ == hit_testable)
+ return;
+
+ hit_testable_ = hit_testable;
+ NoteLayerPropertyChanged();
+}
+
void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) {
LayerImpl::PushPropertiesTo(layer);
SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer);
@@ -63,6 +71,7 @@ void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) {
deadline_in_frames_ = 0u;
layer_impl->SetFallbackSurfaceId(fallback_surface_id_);
layer_impl->SetStretchContentToFillBounds(stretch_content_to_fill_bounds_);
+ layer_impl->SetHitTestable(hit_testable_);
}
void SurfaceLayerImpl::AppendQuads(viz::RenderPass* render_pass,
@@ -93,6 +102,10 @@ void SurfaceLayerImpl::AppendQuads(viz::RenderPass* render_pass,
deadline_in_frames_ = 0u;
}
+bool SurfaceLayerImpl::is_surface_layer() const {
+ return true;
+}
+
viz::SurfaceDrawQuad* SurfaceLayerImpl::CreateSurfaceDrawQuad(
viz::RenderPass* render_pass,
const viz::SurfaceId& primary_surface_id,
diff --git a/chromium/cc/layers/surface_layer_impl.h b/chromium/cc/layers/surface_layer_impl.h
index 380e8b909c1..d51dd6ad9a6 100644
--- a/chromium/cc/layers/surface_layer_impl.h
+++ b/chromium/cc/layers/surface_layer_impl.h
@@ -50,11 +50,15 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
return stretch_content_to_fill_bounds_;
}
+ void SetHitTestable(bool hit_testable);
+ bool hit_testable() const { return hit_testable_; }
+
// LayerImpl overrides.
std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
void PushPropertiesTo(LayerImpl* layer) 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);
@@ -75,6 +79,7 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
base::Optional<uint32_t> deadline_in_frames_;
bool stretch_content_to_fill_bounds_ = false;
+ bool hit_testable_ = false;
DISALLOW_COPY_AND_ASSIGN(SurfaceLayerImpl);
};
diff --git a/chromium/cc/layers/surface_layer_unittest.cc b/chromium/cc/layers/surface_layer_unittest.cc
index 45def505da1..9eb987a0f9e 100644
--- a/chromium/cc/layers/surface_layer_unittest.cc
+++ b/chromium/cc/layers/surface_layer_unittest.cc
@@ -86,6 +86,18 @@ TEST_F(SurfaceLayerTest, UseExistingDeadlineForNewSurfaceLayer) {
EXPECT_EQ(0u, layer->deadline_in_frames());
}
+// This test verifies that if UseInfiniteDeadline() is used on a new
+// SurfaceLayer then the deadline will be max number of frames.
+TEST_F(SurfaceLayerTest, UseInfiniteDeadlineForNewSurfaceLayer) {
+ 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::UseInfiniteDeadline());
+ EXPECT_EQ(std::numeric_limits<uint32_t>::max(), layer->deadline_in_frames());
+}
+
// This test verifies that SurfaceLayer properties are pushed across to
// SurfaceLayerImpl.
TEST_F(SurfaceLayerTest, PushProperties) {
diff --git a/chromium/cc/layers/texture_layer.cc b/chromium/cc/layers/texture_layer.cc
index 935ef9ab5c3..0e55c54f17f 100644
--- a/chromium/cc/layers/texture_layer.cc
+++ b/chromium/cc/layers/texture_layer.cc
@@ -7,7 +7,6 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
-#include "base/memory/ptr_util.h"
#include "base/synchronization/lock.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/simple_enclosed_region.h"
@@ -23,7 +22,8 @@ scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox(
return scoped_refptr<TextureLayer>(new TextureLayer(client));
}
-TextureLayer::TextureLayer(TextureLayerClient* client) : client_(client) {}
+TextureLayer::TextureLayer(TextureLayerClient* client)
+ : client_(client), weak_ptr_factory_(this) {}
TextureLayer::~TextureLayer() = default;
@@ -154,6 +154,15 @@ void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) {
// commit is called complete.
SetNextCommitWaitsForActivation();
}
+ if (host) {
+ // When attached to a new LayerTreHost, all previously registered
+ // SharedBitmapIds will need to be re-sent to the new TextureLayerImpl
+ // representing this layer on the compositor thread.
+ to_register_bitmaps_.insert(
+ std::make_move_iterator(registered_bitmaps_.begin()),
+ std::make_move_iterator(registered_bitmaps_.end()));
+ registered_bitmaps_.clear();
+ }
Layer::SetLayerTreeHost(host);
}
@@ -166,7 +175,8 @@ bool TextureLayer::Update() {
if (client_) {
viz::TransferableResource resource;
std::unique_ptr<viz::SingleReleaseCallback> release_callback;
- if (client_->PrepareTransferableResource(&resource, &release_callback)) {
+ if (client_->PrepareTransferableResource(this, &resource,
+ &release_callback)) {
// Already within a commit, no need to do another one immediately.
bool requires_commit = false;
SetTransferableResourceInternal(resource, std::move(release_callback),
@@ -210,6 +220,49 @@ void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
std::move(release_callback));
needs_set_resource_ = false;
}
+ for (auto& pair : to_register_bitmaps_)
+ texture_layer->RegisterSharedBitmapId(pair.first, pair.second);
+ // Store the registered SharedBitmapIds in case we get a new TextureLayerImpl,
+ // in a new tree, to re-send them to.
+ registered_bitmaps_.insert(
+ std::make_move_iterator(to_register_bitmaps_.begin()),
+ std::make_move_iterator(to_register_bitmaps_.end()));
+ to_register_bitmaps_.clear();
+ for (const auto& id : to_unregister_bitmap_ids_)
+ texture_layer->UnregisterSharedBitmapId(id);
+ to_unregister_bitmap_ids_.clear();
+}
+
+SharedBitmapIdRegistration TextureLayer::RegisterSharedBitmapId(
+ const viz::SharedBitmapId& id,
+ scoped_refptr<CrossThreadSharedBitmap> bitmap) {
+ DCHECK(to_register_bitmaps_.find(id) == to_register_bitmaps_.end());
+ DCHECK(registered_bitmaps_.find(id) == registered_bitmaps_.end());
+ to_register_bitmaps_[id] = std::move(bitmap);
+ base::Erase(to_unregister_bitmap_ids_, id);
+ // This does not SetNeedsCommit() to be as lazy as possible. Notifying a
+ // SharedBitmapId is not needed until it is used, and using it will require
+ // a commit, so we can wait for that commit before forwarding the
+ // notification instead of forcing it to happen as a side effect of this
+ // method.
+ SetNeedsPushProperties();
+ return SharedBitmapIdRegistration(weak_ptr_factory_.GetWeakPtr(), id);
+}
+
+void TextureLayer::UnregisterSharedBitmapId(viz::SharedBitmapId id) {
+ // If we didn't get to sending the registration to the compositor thread yet,
+ // just remove it.
+ to_register_bitmaps_.erase(id);
+ // Since we also track all previously sent registrations, we must remove that
+ // to in order to prevent re-registering on another LayerTreeHost.
+ registered_bitmaps_.erase(id);
+
+ to_unregister_bitmap_ids_.push_back(id);
+ // Unregistering a SharedBitmapId needs to happen eventually to prevent
+ // leaking the SharedMemory in the display compositor. But this attempts to be
+ // lazy and not force a commit prematurely, so just requests a
+ // PushPropertiesTo() without requesting a commit.
+ SetNeedsPushProperties();
}
TextureLayer::TransferableResourceHolder::MainThreadReference::
diff --git a/chromium/cc/layers/texture_layer.h b/chromium/cc/layers/texture_layer.h
index ae19b371308..af32a87c81e 100644
--- a/chromium/cc/layers/texture_layer.h
+++ b/chromium/cc/layers/texture_layer.h
@@ -9,10 +9,13 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "cc/cc_export.h"
#include "cc/layers/layer.h"
+#include "cc/resources/cross_thread_shared_bitmap.h"
+#include "cc/resources/shared_bitmap_id_registrar.h"
#include "components/viz/common/resources/transferable_resource.h"
namespace gpu {
@@ -25,10 +28,14 @@ class SingleReleaseCallback;
namespace cc {
class SingleReleaseCallback;
+class TextureLayer;
class TextureLayerClient;
-// A Layer containing a the rendered output of a plugin instance.
-class CC_EXPORT TextureLayer : public Layer {
+// A Layer containing a the rendered output of a plugin instance. It can be used
+// to display gpu or software resources, depending if the compositor is working
+// in gpu or software compositing mode (the resources must match the compositing
+// mode).
+class CC_EXPORT TextureLayer : public Layer, SharedBitmapIdRegistrar {
public:
class CC_EXPORT TransferableResourceHolder
: public base::RefCountedThreadSafe<TransferableResourceHolder> {
@@ -143,6 +150,17 @@ class CC_EXPORT TextureLayer : public Layer {
bool IsSnapped() override;
void PushPropertiesTo(LayerImpl* layer) override;
+ // Request a mapping from SharedBitmapId to SharedMemory be registered via the
+ // LayerTreeFrameSink with the display compositor. Once this mapping is
+ // registered, the SharedBitmapId can be used in TransferableResources given
+ // to the TextureLayer for display. The SharedBitmapId registration will end
+ // when the returned SharedBitmapIdRegistration object is destroyed.
+ // Implemented as a SharedBitmapIdRegistrar interface so that clients can
+ // have a limited API access.
+ SharedBitmapIdRegistration RegisterSharedBitmapId(
+ const viz::SharedBitmapId& id,
+ scoped_refptr<CrossThreadSharedBitmap> bitmap) override;
+
protected:
explicit TextureLayer(TextureLayerClient* client);
~TextureLayer() override;
@@ -154,6 +172,12 @@ class CC_EXPORT TextureLayer : public Layer {
std::unique_ptr<viz::SingleReleaseCallback> release_callback,
bool requires_commit);
+ // Friends to give access to UnregisterSharedBitmapId().
+ friend SharedBitmapIdRegistration;
+ // Remove a mapping from SharedBitmapId to SharedMemory in the display
+ // compositor.
+ void UnregisterSharedBitmapId(viz::SharedBitmapId id);
+
TextureLayerClient* client_;
bool flipped_ = true;
@@ -168,6 +192,24 @@ class CC_EXPORT TextureLayer : public Layer {
std::unique_ptr<TransferableResourceHolder::MainThreadReference> holder_ref_;
bool needs_set_resource_ = false;
+ // The set of SharedBitmapIds to register with the LayerTreeFrameSink on the
+ // compositor thread. These requests are forwarded to the TextureLayerImpl to
+ // use, then stored in |registered_bitmaps_| to re-send if the
+ // TextureLayerImpl object attached to this layer changes, by moving out of
+ // the LayerTreeHost.
+ base::flat_map<viz::SharedBitmapId, scoped_refptr<CrossThreadSharedBitmap>>
+ to_register_bitmaps_;
+ // The set of previously registered SharedBitmapIds for the current
+ // LayerTreeHost. If the LayerTreeHost changes, these must be re-sent to the
+ // (new) TextureLayerImpl to be re-registered.
+ base::flat_map<viz::SharedBitmapId, scoped_refptr<CrossThreadSharedBitmap>>
+ registered_bitmaps_;
+ // The SharedBitmapIds to unregister on the compositor thread, passed to the
+ // TextureLayerImpl.
+ std::vector<viz::SharedBitmapId> to_unregister_bitmap_ids_;
+
+ base::WeakPtrFactory<TextureLayer> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(TextureLayer);
};
diff --git a/chromium/cc/layers/texture_layer_client.h b/chromium/cc/layers/texture_layer_client.h
index a535d504b54..71c217eee29 100644
--- a/chromium/cc/layers/texture_layer_client.h
+++ b/chromium/cc/layers/texture_layer_client.h
@@ -12,6 +12,7 @@ struct TransferableResource;
}
namespace cc {
+class SharedBitmapIdRegistrar;
class TextureLayerClient {
public:
@@ -19,6 +20,7 @@ class TextureLayerClient {
// Returns false if no new data is available
// and the old mailbox is to be reused.
virtual bool PrepareTransferableResource(
+ SharedBitmapIdRegistrar* bitmap_registar,
viz::TransferableResource* transferable_resource,
std::unique_ptr<viz::SingleReleaseCallback>* release_callback) = 0;
diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc
index b57570f2e40..b0203d5362f 100644
--- a/chromium/cc/layers/texture_layer_impl.cc
+++ b/chromium/cc/layers/texture_layer_impl.cc
@@ -10,10 +10,12 @@
#include <vector>
#include "base/strings/stringprintf.h"
+#include "cc/trees/layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/occlusion.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/resources/bitmap_allocation.h"
#include "components/viz/common/resources/platform_color.h"
#include "components/viz/common/resources/single_release_callback.h"
@@ -24,17 +26,15 @@ TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* tree_impl, int id)
TextureLayerImpl::~TextureLayerImpl() {
FreeTransferableResource();
-}
-void TextureLayerImpl::SetTransferableResource(
- const viz::TransferableResource& resource,
- std::unique_ptr<viz::SingleReleaseCallback> release_callback) {
- DCHECK_EQ(resource.mailbox_holder.mailbox.IsZero(), !release_callback);
- FreeTransferableResource();
- transferable_resource_ = resource;
- release_callback_ = std::move(release_callback);
- own_resource_ = true;
- SetNeedsPushProperties();
+ LayerTreeFrameSink* sink = layer_tree_impl()->layer_tree_frame_sink();
+ // The LayerTreeFrameSink may be gone, in which case there's no need to
+ // unregister anything.
+ if (sink) {
+ for (const auto& pair : registered_bitmaps_) {
+ sink->DidDeleteSharedBitmap(pair.first);
+ }
+ }
}
std::unique_ptr<LayerImpl> TextureLayerImpl::CreateLayerImpl(
@@ -61,6 +61,12 @@ void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) {
std::move(release_callback_));
own_resource_ = false;
}
+ for (auto& pair : to_register_bitmaps_)
+ texture_layer->RegisterSharedBitmapId(pair.first, std::move(pair.second));
+ to_register_bitmaps_.clear();
+ for (const auto& id : to_unregister_bitmap_ids_)
+ texture_layer->UnregisterSharedBitmapId(id);
+ to_unregister_bitmap_ids_.clear();
}
bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
@@ -97,6 +103,25 @@ void TextureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
AppendQuadsData* append_quads_data) {
DCHECK(resource_id_);
+ LayerTreeFrameSink* sink = layer_tree_impl()->layer_tree_frame_sink();
+ for (const auto& pair : to_register_bitmaps_) {
+ // Because we may want to notify a display compositor about this
+ // base::SharedMemory more than one time, we need to be able to keep
+ // making handles to share with it, so we can't close the
+ // base::SharedMemory.
+ mojo::ScopedSharedBufferHandle handle =
+ viz::bitmap_allocation::DuplicateWithoutClosingMappedBitmap(
+ pair.second->shared_memory(), pair.second->size(),
+ pair.second->format());
+ sink->DidAllocateSharedBitmap(std::move(handle), pair.first);
+ }
+ // All |to_register_bitmaps_| have been registered above, so we can move them
+ // all to the |registered_bitmaps_|.
+ registered_bitmaps_.insert(
+ std::make_move_iterator(to_register_bitmaps_.begin()),
+ std::make_move_iterator(to_register_bitmaps_.end()));
+ to_register_bitmaps_.clear();
+
SkColor bg_color =
blend_background_color_ ? background_color() : SK_ColorTRANSPARENT;
bool are_contents_opaque =
@@ -143,6 +168,19 @@ SimpleEnclosedRegion TextureLayerImpl::VisibleOpaqueRegion() const {
void TextureLayerImpl::ReleaseResources() {
FreeTransferableResource();
resource_id_ = 0;
+
+ // The LayerTreeFrameSink is gone and being replaced, so we will have to
+ // re-register all SharedBitmapIds on the new LayerTreeFrameSink. We don't
+ // need to do that until the SharedBitmapIds will be used, in AppendQuads(),
+ // but we mark them all as to be registered here.
+ to_register_bitmaps_.insert(
+ std::make_move_iterator(registered_bitmaps_.begin()),
+ std::make_move_iterator(registered_bitmaps_.end()));
+ registered_bitmaps_.clear();
+ // The |to_unregister_bitmap_ids_| are kept since the active layer will re-
+ // register its SharedBitmapIds with a new LayerTreeFrameSink in the future,
+ // so we must remember that we want to unregister it (or avoid registering at
+ // all) instead.
}
void TextureLayerImpl::SetPremultipliedAlpha(bool premultiplied_alpha) {
@@ -186,12 +224,60 @@ void TextureLayerImpl::SetVertexOpacity(const float vertex_opacity[4]) {
SetNeedsPushProperties();
}
+void TextureLayerImpl::SetTransferableResource(
+ const viz::TransferableResource& resource,
+ std::unique_ptr<viz::SingleReleaseCallback> release_callback) {
+ DCHECK_EQ(resource.mailbox_holder.mailbox.IsZero(), !release_callback);
+ FreeTransferableResource();
+ transferable_resource_ = resource;
+ release_callback_ = std::move(release_callback);
+ own_resource_ = true;
+ SetNeedsPushProperties();
+}
+
+void TextureLayerImpl::RegisterSharedBitmapId(
+ viz::SharedBitmapId id,
+ scoped_refptr<CrossThreadSharedBitmap> bitmap) {
+ // If a TextureLayer leaves and rejoins a tree without the TextureLayerImpl
+ // being destroyed, then it will re-request registration of ids that are still
+ // registered on the impl side, so we can just ignore these requests.
+ if (registered_bitmaps_.find(id) == registered_bitmaps_.end()) {
+ // If this is a pending layer, these will be moved to the active layer when
+ // we PushPropertiesTo(). Otherwise, we don't need to notify these to the
+ // LayerTreeFrameSink until we're going to use them, so defer it until
+ // AppendQuads().
+ to_register_bitmaps_[id] = std::move(bitmap);
+ }
+ base::Erase(to_unregister_bitmap_ids_, id);
+ SetNeedsPushProperties();
+}
+
+void TextureLayerImpl::UnregisterSharedBitmapId(viz::SharedBitmapId id) {
+ if (IsActive()) {
+ LayerTreeFrameSink* sink = layer_tree_impl()->layer_tree_frame_sink();
+ if (sink && registered_bitmaps_.find(id) != registered_bitmaps_.end())
+ sink->DidDeleteSharedBitmap(id);
+ to_register_bitmaps_.erase(id);
+ registered_bitmaps_.erase(id);
+ } else {
+ // The active layer will unregister. We do this because it may be using the
+ // SharedBitmapId, so we should remove the SharedBitmapId only after we've
+ // had a chance to replace it with activation.
+ to_unregister_bitmap_ids_.push_back(id);
+ SetNeedsPushProperties();
+ }
+}
+
const char* TextureLayerImpl::LayerTypeAsString() const {
return "cc::TextureLayerImpl";
}
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
@@ -202,6 +288,9 @@ 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 d6889023b20..49b6be2ffa1 100644
--- a/chromium/cc/layers/texture_layer_impl.h
+++ b/chromium/cc/layers/texture_layer_impl.h
@@ -8,10 +8,12 @@
#include <string>
#include "base/callback.h"
+#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "cc/cc_export.h"
#include "cc/layers/layer_impl.h"
+#include "cc/resources/cross_thread_shared_bitmap.h"
#include "components/viz/common/resources/transferable_resource.h"
namespace viz {
@@ -60,6 +62,20 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
const viz::TransferableResource& resource,
std::unique_ptr<viz::SingleReleaseCallback> release_callback);
+ // These methods notify the display compositor, through the
+ // CompositorFrameSink, of the existance of a SharedBitmapId and its
+ // mapping to a SharedMemory in |bitmap|. Then this SharedBitmapId can be used
+ // in TransferableResources inserted on the layer while it is registered. If
+ // the layer is destroyed, the SharedBitmapId will be unregistered
+ // automatically, and if the CompositorFrameSink is replaced, it will be
+ // re-registered on the new one. The SharedMemory must be kept alive while it
+ // is registered.
+ // If this is a pending layer, the registration is deferred to the active
+ // layer.
+ void RegisterSharedBitmapId(viz::SharedBitmapId id,
+ scoped_refptr<CrossThreadSharedBitmap> bitmap);
+ void UnregisterSharedBitmapId(viz::SharedBitmapId id);
+
private:
TextureLayerImpl(LayerTreeImpl* tree_impl, int id);
@@ -87,6 +103,26 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
viz::ResourceId resource_id_ = 0;
std::unique_ptr<viz::SingleReleaseCallback> release_callback_;
+ // As a pending layer, the set of SharedBitmapIds and the underlying
+ // base::SharedMemory that must be notified to the display compositor through
+ // the LayerTreeFrameSink. These will be passed to the active layer. As an
+ // active layer, the set of SharedBitmapIds that need to be registered but
+ // have not been yet, since it is done lazily.
+ base::flat_map<viz::SharedBitmapId, scoped_refptr<CrossThreadSharedBitmap>>
+ to_register_bitmaps_;
+
+ // For active layers only. The set of SharedBitmapIds and ownership of the
+ // underlying base::SharedMemory that have been notified to the display
+ // compositor through the LayerTreeFrameSink. These will need to be
+ // re-registered if the LayerTreeFrameSink changes (ie ReleaseResources()
+ // occurs).
+ base::flat_map<viz::SharedBitmapId, scoped_refptr<CrossThreadSharedBitmap>>
+ registered_bitmaps_;
+
+ // As a pending layer, the set of SharedBitmapIds that the active layer should
+ // unregister.
+ std::vector<viz::SharedBitmapId> to_unregister_bitmap_ids_;
+
DISALLOW_COPY_AND_ASSIGN(TextureLayerImpl);
};
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index 137135e85ee..24463ef1a26 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -38,8 +38,12 @@
#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/resources/bitmap_allocation.h"
#include "components/viz/common/resources/returned_resource.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"
#include "components/viz/test/test_layer_tree_frame_sink.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -129,13 +133,14 @@ struct CommonResourceObjects {
resource2_ = viz::TransferableResource::MakeGL(
mailbox_name2_, GL_LINEAR, arbitrary_target2, sync_token2_);
gfx::Size size(128, 128);
- shared_bitmap_ = manager->AllocateSharedBitmap(size);
+ shared_bitmap_ = manager->AllocateSharedBitmap(size, viz::RGBA_8888);
DCHECK(shared_bitmap_);
release_callback3_ =
base::Bind(&MockReleaseCallback::Release2,
base::Unretained(&mock_callback_), shared_bitmap_.get());
resource3_ = viz::TransferableResource::MakeSoftware(
- shared_bitmap_->id(), shared_bitmap_->sequence_number(), size);
+ shared_bitmap_->id(), shared_bitmap_->sequence_number(), size,
+ viz::RGBA_8888);
}
using RepeatingReleaseCallback =
@@ -925,6 +930,7 @@ class TextureLayerNoExtraCommitForMailboxTest
public:
// TextureLayerClient implementation.
bool PrepareTransferableResource(
+ SharedBitmapIdRegistrar* bitmap_registrar,
viz::TransferableResource* resource,
std::unique_ptr<viz::SingleReleaseCallback>* release_callback) override {
if (layer_tree_host()->SourceFrameNumber() == 1) {
@@ -1003,6 +1009,7 @@ class TextureLayerChangeInvisibleMailboxTest
// TextureLayerClient implementation.
bool PrepareTransferableResource(
+ SharedBitmapIdRegistrar* bitmap_registrar,
viz::TransferableResource* resource,
std::unique_ptr<viz::SingleReleaseCallback>* release_callback) override {
++prepare_called_;
@@ -1122,6 +1129,7 @@ class TextureLayerReleaseResourcesBase
public:
// TextureLayerClient implementation.
bool PrepareTransferableResource(
+ SharedBitmapIdRegistrar* bitmap_registrar,
viz::TransferableResource* resource,
std::unique_ptr<viz::SingleReleaseCallback>* release_callback) override {
*resource = viz::TransferableResource::MakeGL(
@@ -1329,5 +1337,557 @@ class TextureLayerWithResourceImplThreadDeleted : public LayerTreeTest {
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerWithResourceImplThreadDeleted);
+class StubTextureLayerClient : public TextureLayerClient {
+ public:
+ // TextureLayerClient implementation.
+ bool PrepareTransferableResource(
+ SharedBitmapIdRegistrar* bitmap_registrar,
+ viz::TransferableResource* resource,
+ std::unique_ptr<viz::SingleReleaseCallback>* release_callback) override {
+ return false;
+ }
+};
+
+class SoftwareLayerTreeHostClient : public StubLayerTreeHostClient {
+ public:
+ SoftwareLayerTreeHostClient() = default;
+ ~SoftwareLayerTreeHostClient() override = default;
+
+ // Caller responsible for unsetting this and maintaining the host's lifetime.
+ void SetLayerTreeHost(LayerTreeHost* host) { host_ = host; }
+
+ // StubLayerTreeHostClient overrides.
+ void RequestNewLayerTreeFrameSink() override {
+ auto sink = FakeLayerTreeFrameSink::CreateSoftware();
+ frame_sink_ = sink.get();
+ host_->SetLayerTreeFrameSink(std::move(sink));
+ }
+
+ FakeLayerTreeFrameSink* frame_sink() const { return frame_sink_; }
+
+ private:
+ FakeLayerTreeFrameSink* frame_sink_ = nullptr;
+ LayerTreeHost* host_ = nullptr;
+};
+
+class SoftwareTextureLayerTest : public LayerTreeTest {
+ protected:
+ void SetupTree() override {
+ root_ = Layer::Create();
+ root_->SetBounds(gfx::Size(10, 10));
+
+ // A drawable layer so that frames always get drawn.
+ solid_color_layer_ = SolidColorLayer::Create();
+ solid_color_layer_->SetIsDrawable(true);
+ solid_color_layer_->SetBackgroundColor(SK_ColorRED);
+ solid_color_layer_->SetBounds(gfx::Size(10, 10));
+ root_->AddChild(solid_color_layer_);
+
+ texture_layer_ = TextureLayer::CreateForMailbox(&client_);
+ texture_layer_->SetIsDrawable(true);
+ texture_layer_->SetBounds(gfx::Size(10, 10));
+ layer_tree_host()->SetRootLayer(root_);
+ LayerTreeTest::SetupTree();
+ }
+
+ 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 {
+ constexpr bool disable_display_vsync = false;
+ bool synchronous_composite =
+ !HasImplThread() &&
+ !layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
+ auto sink = std::make_unique<viz::TestLayerTreeFrameSink>(
+ nullptr, nullptr, shared_bitmap_manager(), gpu_memory_buffer_manager(),
+ renderer_settings, ImplThreadTaskRunner(), synchronous_composite,
+ disable_display_vsync, refresh_rate);
+ frame_sink_ = sink.get();
+ num_frame_sinks_created_++;
+ return sink;
+ }
+
+ std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread(
+ scoped_refptr<viz::ContextProvider> compositor_context_provider)
+ override {
+ return viz::FakeOutputSurface::CreateSoftware(
+ std::make_unique<viz::SoftwareOutputDevice>());
+ }
+
+ StubTextureLayerClient client_;
+ scoped_refptr<Layer> root_;
+ scoped_refptr<SolidColorLayer> solid_color_layer_;
+ scoped_refptr<TextureLayer> texture_layer_;
+ viz::TestLayerTreeFrameSink* frame_sink_ = nullptr;
+ int num_frame_sinks_created_ = 0;
+};
+
+class SoftwareTextureLayerSwitchTreesTest : public SoftwareTextureLayerTest {
+ protected:
+ void BeginTest() override {
+ PostSetNeedsCommitToMainThread();
+
+ gfx::Size size(1, 1);
+ 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_, 0, gfx::Size(1, 1),
+ viz::RGBA_8888),
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce([](const gpu::SyncToken&, bool) {})));
+ break;
+ case 2:
+ // When the layer is removed from the tree, the bitmap should be
+ // unregistered.
+ texture_layer_->RemoveFromParent();
+ break;
+ case 3:
+ // When the layer is added to a new tree, the SharedBitmapId is
+ // registered again.
+ root_->AddChild(texture_layer_);
+ break;
+ case 4:
+ // If the layer is removed and added back to the same tree in one
+ // commit, there should be no side effects, the bitmap stays
+ // registered.
+ texture_layer_->RemoveFromParent();
+ root_->AddChild(texture_layer_);
+ break;
+ case 5:
+ // Release the TransferableResource before shutdown.
+ texture_layer_->ClearClient();
+ break;
+ case 6:
+ EndTest();
+ }
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ switch (step_) {
+ case 0:
+ // Before commit 1, the |texture_layer_| has no SharedBitmapId yet.
+ EXPECT_EQ(0u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ case 1:
+ // For commit 1, we added a SharedBitmapId to |texture_layer_|.
+ EXPECT_EQ(1u, frame_sink_->owned_bitmaps().size());
+ EXPECT_EQ(*frame_sink_->owned_bitmaps().begin(), id_);
+ verified_frames_++;
+ break;
+ case 2:
+ // For commit 2, we removed |texture_layer_| from the tree.
+ EXPECT_EQ(0u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ case 3:
+ // For commit 3, we added |texture_layer_| back to the tree.
+ EXPECT_EQ(1u, frame_sink_->owned_bitmaps().size());
+ EXPECT_EQ(*frame_sink_->owned_bitmaps().begin(), id_);
+ verified_frames_++;
+ break;
+ case 4:
+ // For commit 3, we removed+added |texture_layer_| back to the tree.
+ EXPECT_EQ(1u, frame_sink_->owned_bitmaps().size());
+ EXPECT_EQ(*frame_sink_->owned_bitmaps().begin(), id_);
+ verified_frames_++;
+ break;
+ }
+ }
+
+ void AfterTest() override { EXPECT_EQ(5, verified_frames_); }
+
+ int step_ = 0;
+ int verified_frames_ = 0;
+ viz::SharedBitmapId id_;
+ SharedBitmapIdRegistration registration_;
+ scoped_refptr<CrossThreadSharedBitmap> bitmap_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerSwitchTreesTest);
+
+class SoftwareTextureLayerMultipleRegisterTest
+ : public SoftwareTextureLayerTest {
+ protected:
+ void BeginTest() override {
+ PostSetNeedsCommitToMainThread();
+
+ gfx::Size size(1, 1);
+ viz::ResourceFormat format = viz::RGBA_8888;
+
+ id1_ = viz::SharedBitmap::GenerateId();
+ bitmap1_ = base::MakeRefCounted<CrossThreadSharedBitmap>(
+ id1_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size,
+ format);
+ id2_ = viz::SharedBitmap::GenerateId();
+ bitmap2_ = base::MakeRefCounted<CrossThreadSharedBitmap>(
+ id2_, 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 2 SharedBitmapIds, which should be given to the
+ // LayerTreeFrameSink.
+ registration1_ = texture_layer_->RegisterSharedBitmapId(id1_, bitmap1_);
+ registration2_ = texture_layer_->RegisterSharedBitmapId(id2_, bitmap2_);
+ // 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(id1_, 0, gfx::Size(1, 1),
+ viz::RGBA_8888),
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce([](const gpu::SyncToken&, bool) {})));
+ break;
+ case 2:
+ // Drop one registration, and force a commit and SubmitCompositorFrame
+ // so that we can see it.
+ registration2_ = SharedBitmapIdRegistration();
+ texture_layer_->SetNeedsDisplay();
+ break;
+ case 3:
+ // Drop the other registration.
+ texture_layer_->ClearClient();
+ registration1_ = SharedBitmapIdRegistration();
+ break;
+ case 4:
+ EndTest();
+ }
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ switch (step_) {
+ case 0:
+ // Before commit 1, the |texture_layer_| has no SharedBitmapId yet.
+ EXPECT_EQ(0u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ case 1:
+ // For commit 1, we added 2 SharedBitmapIds to |texture_layer_|.
+ EXPECT_EQ(2u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ case 2:
+ // For commit 2, we removed one SharedBitmapId.
+ EXPECT_EQ(1u, frame_sink_->owned_bitmaps().size());
+ EXPECT_EQ(*frame_sink_->owned_bitmaps().begin(), id1_);
+ verified_frames_++;
+ break;
+ case 3:
+ // For commit 3, we removed the other SharedBitmapId.
+ EXPECT_EQ(0u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ }
+ }
+
+ void AfterTest() override { EXPECT_EQ(4, verified_frames_); }
+
+ int step_ = 0;
+ int verified_frames_ = 0;
+ viz::SharedBitmapId id1_;
+ viz::SharedBitmapId id2_;
+ SharedBitmapIdRegistration registration1_;
+ SharedBitmapIdRegistration registration2_;
+ scoped_refptr<CrossThreadSharedBitmap> bitmap1_;
+ scoped_refptr<CrossThreadSharedBitmap> bitmap2_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerMultipleRegisterTest);
+
+class SoftwareTextureLayerRegisterUnregisterTest
+ : public SoftwareTextureLayerTest {
+ protected:
+ void BeginTest() override {
+ PostSetNeedsCommitToMainThread();
+
+ gfx::Size size(1, 1);
+ viz::ResourceFormat format = viz::RGBA_8888;
+
+ id1_ = viz::SharedBitmap::GenerateId();
+ bitmap1_ = base::MakeRefCounted<CrossThreadSharedBitmap>(
+ id1_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size,
+ format);
+ id2_ = viz::SharedBitmap::GenerateId();
+ bitmap2_ = base::MakeRefCounted<CrossThreadSharedBitmap>(
+ id2_, 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 2 SharedBitmapIds, which would be given to the
+ // LayerTreeFrameSink. But we unregister one.
+ {
+ registration1_ =
+ texture_layer_->RegisterSharedBitmapId(id1_, bitmap1_);
+ // We explicitly drop this registration by letting it go out of scope
+ // and being destroyed. Versus the registration1_ which we drop by
+ // assigning an empty registration to it. Both should do the same
+ // thing.
+ SharedBitmapIdRegistration temp_reg =
+ texture_layer_->RegisterSharedBitmapId(id2_, bitmap2_);
+ }
+ // 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(id1_, 0, gfx::Size(1, 1),
+ viz::RGBA_8888),
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce([](const gpu::SyncToken&, bool) {})));
+ break;
+ case 2:
+ // Drop the other registration.
+ texture_layer_->ClearClient();
+ registration1_ = SharedBitmapIdRegistration();
+ break;
+ case 3:
+ EndTest();
+ }
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ switch (step_) {
+ case 0:
+ // Before commit 1, the |texture_layer_| has no SharedBitmapId yet.
+ EXPECT_EQ(0u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ case 1:
+ // For commit 1, we added 1 SharedBitmapId to |texture_layer_|.
+ EXPECT_EQ(1u, frame_sink_->owned_bitmaps().size());
+ EXPECT_EQ(*frame_sink_->owned_bitmaps().begin(), id1_);
+ verified_frames_++;
+ break;
+ case 2:
+ // For commit 2, we removed the other SharedBitmapId.
+ EXPECT_EQ(0u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ }
+ }
+
+ void AfterTest() override { EXPECT_EQ(3, verified_frames_); }
+
+ int step_ = 0;
+ int verified_frames_ = 0;
+ viz::SharedBitmapId id1_;
+ viz::SharedBitmapId id2_;
+ SharedBitmapIdRegistration registration1_;
+ scoped_refptr<CrossThreadSharedBitmap> bitmap1_;
+ scoped_refptr<CrossThreadSharedBitmap> bitmap2_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerRegisterUnregisterTest);
+
+class SoftwareTextureLayerLoseFrameSinkTest : public SoftwareTextureLayerTest {
+ protected:
+ void BeginTest() override {
+ PostSetNeedsCommitToMainThread();
+
+ gfx::Size size(1, 1);
+ 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_, 0, gfx::Size(1, 1),
+ viz::RGBA_8888),
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce([](const gpu::SyncToken&, bool) {})));
+ break;
+ case 2:
+ // The frame sink is lost. The host will make a new one and submit
+ // another frame, with the id being registered again.
+ layer_tree_host()->SetVisible(false);
+ first_frame_sink_ =
+ 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_, 0, gfx::Size(1, 1),
+ viz::RGBA_8888),
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce([](const gpu::SyncToken&, bool) {})));
+ break;
+ case 3:
+ // Release the TransferableResource before shutdown.
+ texture_layer_->ClearClient();
+ break;
+ case 4:
+ EndTest();
+ }
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ switch (step_) {
+ case 0:
+ // Before commit 1, the |texture_layer_| has no SharedBitmapId yet.
+ EXPECT_EQ(0u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ case 1:
+ // For commit 1, we added a SharedBitmapId to |texture_layer_|.
+ EXPECT_EQ(1, num_frame_sinks_created_);
+ EXPECT_EQ(1u, frame_sink_->owned_bitmaps().size());
+ EXPECT_EQ(*frame_sink_->owned_bitmaps().begin(), id_);
+ verified_frames_++;
+ break;
+ case 2:
+ // For commit 2, we should still have the SharedBitmapId in the new
+ // frame sink.
+ EXPECT_EQ(2, num_frame_sinks_created_);
+ EXPECT_EQ(1u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ }
+ }
+
+ void AfterTest() override { EXPECT_EQ(3, verified_frames_); }
+
+ int step_ = 0;
+ int verified_frames_ = 0;
+ viz::SharedBitmapId id_;
+ SharedBitmapIdRegistration registration_;
+ scoped_refptr<CrossThreadSharedBitmap> bitmap_;
+ // Keeps a pointer value of the first frame sink, which will be removed
+ // from the host and destroyed.
+ void* first_frame_sink_;
+};
+
+// TODO(crbug.com/829923): Flaky with a heap-use-after-free.
+// SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerLoseFrameSinkTest);
+
+class SoftwareTextureLayerUnregisterRegisterTest
+ : public SoftwareTextureLayerTest {
+ protected:
+ void BeginTest() override {
+ PostSetNeedsCommitToMainThread();
+
+ gfx::Size size(1, 1);
+ 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_);
+
+ // We do a Register request, Unregister request, and then another
+ // Register request. The final register request should stick.
+ // And registers 2 SharedBitmapIds, which would be given to the
+ // LayerTreeFrameSink. But we unregister one.
+ {
+ // Register-Unregister-
+ SharedBitmapIdRegistration temp_reg =
+ texture_layer_->RegisterSharedBitmapId(id_, bitmap_);
+ }
+ // Register.
+ 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_, 0, gfx::Size(1, 1),
+ viz::RGBA_8888),
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce([](const gpu::SyncToken&, bool) {})));
+ break;
+ case 2:
+ // Release the TransferableResource before shutdown.
+ texture_layer_->ClearClient();
+ break;
+ case 3:
+ EndTest();
+ }
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ switch (step_) {
+ case 0:
+ // Before commit 1, the |texture_layer_| has no SharedBitmapId yet.
+ EXPECT_EQ(0u, frame_sink_->owned_bitmaps().size());
+ verified_frames_++;
+ break;
+ case 1:
+ // For commit 1, we added 1 SharedBitmapId to |texture_layer_|.
+ EXPECT_EQ(1u, frame_sink_->owned_bitmaps().size());
+ EXPECT_EQ(*frame_sink_->owned_bitmaps().begin(), id_);
+ verified_frames_++;
+ break;
+ }
+ }
+
+ void AfterTest() override { EXPECT_EQ(2, verified_frames_); }
+
+ int step_ = 0;
+ int verified_frames_ = 0;
+ viz::SharedBitmapId id_;
+ SharedBitmapIdRegistration registration_;
+ scoped_refptr<CrossThreadSharedBitmap> bitmap_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerUnregisterRegisterTest);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/touch_action_region.cc b/chromium/cc/layers/touch_action_region.cc
index 9d516a0dff8..c61b1377038 100644
--- a/chromium/cc/layers/touch_action_region.cc
+++ b/chromium/cc/layers/touch_action_region.cc
@@ -4,7 +4,6 @@
#include "cc/layers/touch_action_region.h"
-#include "base/memory/ptr_util.h"
#include "ui/gfx/geometry/rect.h"
namespace cc {
diff --git a/chromium/cc/layers/ui_resource_layer.cc b/chromium/cc/layers/ui_resource_layer.cc
index b95ca27bd7c..364e97c09ed 100644
--- a/chromium/cc/layers/ui_resource_layer.cc
+++ b/chromium/cc/layers/ui_resource_layer.cc
@@ -4,7 +4,6 @@
#include "cc/layers/ui_resource_layer.h"
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "cc/layers/ui_resource_layer_impl.h"
#include "cc/resources/scoped_ui_resource.h"
diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc
index 05bbba27b92..d431a96572c 100644
--- a/chromium/cc/layers/video_layer_impl.cc
+++ b/chromium/cc/layers/video_layer_impl.cc
@@ -101,10 +101,13 @@ bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
return false;
if (!updater_) {
- updater_.reset(new VideoResourceUpdater(
+ const LayerTreeSettings& settings = layer_tree_impl()->settings();
+ updater_ = std::make_unique<VideoResourceUpdater>(
layer_tree_impl()->context_provider(),
+ layer_tree_impl()->layer_tree_frame_sink(),
layer_tree_impl()->resource_provider(),
- layer_tree_impl()->settings().use_stream_video_draw_quad));
+ settings.use_stream_video_draw_quad,
+ settings.resource_settings.use_gpu_memory_buffer_resources);
}
updater_->ObtainFrameResources(frame_);
return true;
diff --git a/chromium/cc/paint/BUILD.gn b/chromium/cc/paint/BUILD.gn
index fa8e19b69db..535acba1472 100644
--- a/chromium/cc/paint/BUILD.gn
+++ b/chromium/cc/paint/BUILD.gn
@@ -24,6 +24,7 @@ cc_component("paint") {
"filter_operation.h",
"filter_operations.cc",
"filter_operations.h",
+ "image_analysis_state.h",
"image_animation_count.h",
"image_id.h",
"image_provider.cc",
@@ -134,3 +135,17 @@ fuzzer_test("paint_op_buffer_eq_fuzzer") {
"//cc/paint",
]
}
+
+fuzzer_test("transfer_cache_fuzzer") {
+ sources = [
+ "transfer_cache_fuzzer.cc",
+ ]
+
+ libfuzzer_options = [ "max_len=4096" ]
+
+ deps = [
+ "//cc:test_support",
+ "//cc/paint",
+ "//components/viz/test:test_support",
+ ]
+}
diff --git a/chromium/cc/paint/DEPS b/chromium/cc/paint/DEPS
index 75d19a3fc61..3761569771d 100644
--- a/chromium/cc/paint/DEPS
+++ b/chromium/cc/paint/DEPS
@@ -2,4 +2,7 @@ specific_include_rules = {
"paint_op_buffer_fuzzer.cc": [
"+components/viz/test",
],
+ "transfer_cache_fuzzer.cc": [
+ "+components/viz/test",
+ ],
}
diff --git a/chromium/cc/paint/color_space_transfer_cache_entry.cc b/chromium/cc/paint/color_space_transfer_cache_entry.cc
index 43765c4af2f..adde3371f4e 100644
--- a/chromium/cc/paint/color_space_transfer_cache_entry.cc
+++ b/chromium/cc/paint/color_space_transfer_cache_entry.cc
@@ -46,8 +46,8 @@ size_t ServiceColorSpaceTransferCacheEntry::CachedSize() const {
bool ServiceColorSpaceTransferCacheEntry::Deserialize(
GrContext* context,
- base::span<uint8_t> data) {
- base::Pickle pickle(reinterpret_cast<char*>(data.data()), data.size());
+ base::span<const uint8_t> data) {
+ base::Pickle pickle(reinterpret_cast<const char*>(data.data()), data.size());
base::PickleIterator iterator(pickle);
if (!IPC::ParamTraits<gfx::ColorSpace>::Read(&pickle, &iterator,
&color_space_))
diff --git a/chromium/cc/paint/color_space_transfer_cache_entry.h b/chromium/cc/paint/color_space_transfer_cache_entry.h
index a31467ebab4..baeeb4ce68d 100644
--- a/chromium/cc/paint/color_space_transfer_cache_entry.h
+++ b/chromium/cc/paint/color_space_transfer_cache_entry.h
@@ -44,7 +44,7 @@ class CC_PAINT_EXPORT ServiceColorSpaceTransferCacheEntry final
ServiceColorSpaceTransferCacheEntry();
~ServiceColorSpaceTransferCacheEntry() override;
size_t CachedSize() const override;
- bool Deserialize(GrContext* context, base::span<uint8_t> data) override;
+ bool Deserialize(GrContext* context, base::span<const uint8_t> data) override;
const gfx::ColorSpace& color_space() const { return color_space_; }
diff --git a/chromium/cc/paint/decode_stashing_image_provider.cc b/chromium/cc/paint/decode_stashing_image_provider.cc
index e995f51b28d..f8b4f940c05 100644
--- a/chromium/cc/paint/decode_stashing_image_provider.cc
+++ b/chromium/cc/paint/decode_stashing_image_provider.cc
@@ -15,8 +15,8 @@ DecodeStashingImageProvider::~DecodeStashingImageProvider() = default;
ImageProvider::ScopedDecodedDrawImage
DecodeStashingImageProvider::GetDecodedDrawImage(const DrawImage& draw_image) {
auto decode = source_provider_->GetDecodedDrawImage(draw_image);
- if (!decode)
- return ScopedDecodedDrawImage();
+ if (!decode.needs_unlock())
+ return decode;
// No need to add any destruction callback to the returned image. The images
// decoded here match the lifetime of this provider.
diff --git a/chromium/cc/paint/discardable_image_map.cc b/chromium/cc/paint/discardable_image_map.cc
index e963a143837..232dab6a1d4 100644
--- a/chromium/cc/paint/discardable_image_map.cc
+++ b/chromium/cc/paint/discardable_image_map.cc
@@ -11,9 +11,9 @@
#include "base/auto_reset.h"
#include "base/containers/adapters.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
+#include "cc/paint/paint_filter.h"
#include "cc/paint/paint_op_buffer.h"
#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -124,6 +124,26 @@ class DiscardableImageGenerator {
}
private:
+ class ImageGatheringProvider : public ImageProvider {
+ public:
+ ImageGatheringProvider(DiscardableImageGenerator* generator,
+ const gfx::Rect& op_rect)
+ : generator_(generator), op_rect_(op_rect) {}
+ ~ImageGatheringProvider() override = default;
+
+ ScopedDecodedDrawImage GetDecodedDrawImage(
+ const DrawImage& draw_image) override {
+ generator_->AddImage(draw_image.paint_image(),
+ SkRect::Make(draw_image.src_rect()), op_rect_,
+ SkMatrix::I(), draw_image.filter_quality());
+ return ScopedDecodedDrawImage();
+ }
+
+ private:
+ DiscardableImageGenerator* generator_;
+ gfx::Rect op_rect_;
+ };
+
// Adds discardable images from |buffer| to the set of images tracked by
// this generator. If |buffer| is being used in a DrawOp that requires
// rasterization of the buffer as a pre-processing step for execution of the
@@ -144,12 +164,13 @@ class DiscardableImageGenerator {
// TODO(khushalsagar): Optimize out save/restore blocks if there are no
// images in the draw ops between them.
for (auto* op : PaintOpBuffer::Iterator(buffer)) {
- if (!op->IsDrawOp()) {
+ // We need to play non-draw ops on the SkCanvas since they can affect the
+ // transform/clip state.
+ if (!op->IsDrawOp())
op->Raster(canvas, params);
+
+ if (!PaintOp::OpHasDiscardableImages(op))
continue;
- } else if (!PaintOp::OpHasDiscardableImages(op)) {
- continue;
- }
gfx::Rect op_rect;
base::Optional<gfx::Rect> local_op_rect;
@@ -202,9 +223,10 @@ class DiscardableImageGenerator {
gfx::Rect transformed_rect;
SkRect op_rect;
- if (!PaintOp::GetBounds(op, &op_rect)) {
+ if (!op->IsDrawOp() || !PaintOp::GetBounds(op, &op_rect)) {
// If we can't provide a conservative bounding rect for the op, assume it
// covers the complete current clip.
+ // TODO(khushalsagar): See if we can do something better for non-draw ops.
transformed_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(clip_rect));
} else {
const PaintFlags* flags =
@@ -247,34 +269,48 @@ class DiscardableImageGenerator {
void AddImageFromFlags(const gfx::Rect& op_rect,
const PaintFlags& flags,
const SkMatrix& ctm) {
- if (!flags.getShader())
+ AddImageFromShader(op_rect, flags.getShader(), ctm,
+ flags.getFilterQuality());
+ AddImageFromFilter(op_rect, flags.getImageFilter().get());
+ }
+
+ void AddImageFromShader(const gfx::Rect& op_rect,
+ const PaintShader* shader,
+ const SkMatrix& ctm,
+ SkFilterQuality filter_quality) {
+ if (!shader || !shader->has_discardable_images())
return;
- if (flags.getShader()->shader_type() == PaintShader::Type::kImage) {
- const PaintImage& paint_image = flags.getShader()->paint_image();
+ if (shader->shader_type() == PaintShader::Type::kImage) {
+ const PaintImage& paint_image = shader->paint_image();
SkMatrix matrix = ctm;
- matrix.postConcat(flags.getShader()->GetLocalMatrix());
+ matrix.postConcat(shader->GetLocalMatrix());
AddImage(paint_image,
SkRect::MakeWH(paint_image.width(), paint_image.height()),
- op_rect, matrix, flags.getFilterQuality());
- } else if (flags.getShader()->shader_type() ==
- PaintShader::Type::kPaintRecord &&
- flags.getShader()->paint_record()->HasDiscardableImages()) {
+ op_rect, matrix, filter_quality);
+ return;
+ }
+
+ if (shader->shader_type() == PaintShader::Type::kPaintRecord) {
+ // For record backed shaders, only analyze them if they have animated
+ // images.
+ if (shader->image_analysis_state() ==
+ ImageAnalysisState::kNoAnimatedImages) {
+ return;
+ }
+
SkRect scaled_tile_rect;
- if (!flags.getShader()->GetRasterizationTileRect(ctm,
- &scaled_tile_rect)) {
+ if (!shader->GetRasterizationTileRect(ctm, &scaled_tile_rect)) {
return;
}
PaintTrackingCanvas canvas(scaled_tile_rect.width(),
scaled_tile_rect.height());
- canvas.setMatrix(SkMatrix::MakeRectToRect(flags.getShader()->tile(),
- scaled_tile_rect,
- SkMatrix::kFill_ScaleToFit));
- base::AutoReset<bool> auto_reset(&iterating_record_shaders_, true);
+ canvas.setMatrix(SkMatrix::MakeRectToRect(
+ shader->tile(), scaled_tile_rect, SkMatrix::kFill_ScaleToFit));
+ base::AutoReset<bool> auto_reset(&only_gather_animated_images_, true);
size_t prev_image_set_size = image_set_.size();
- GatherDiscardableImages(flags.getShader()->paint_record().get(), &op_rect,
- &canvas);
+ GatherDiscardableImages(shader->paint_record().get(), &op_rect, &canvas);
// We only track animated images for PaintShaders. If we added any entry
// to the |image_set_|, this shader any has animated images.
@@ -282,9 +318,29 @@ class DiscardableImageGenerator {
// PaintShader here since the analysis is done on the main thread, before
// the PaintOpBuffer is used for rasterization.
DCHECK_GE(image_set_.size(), prev_image_set_size);
- if (image_set_.size() > prev_image_set_size)
- const_cast<PaintShader*>(flags.getShader())->set_has_animated_images();
+ const bool has_animated_images = image_set_.size() > prev_image_set_size;
+ const_cast<PaintShader*>(shader)->set_has_animated_images(
+ has_animated_images);
+ }
+ }
+
+ void AddImageFromFilter(const gfx::Rect& op_rect, const PaintFilter* filter) {
+ // Only analyze filters if they have animated images.
+ if (!filter || !filter->has_discardable_images() ||
+ filter->image_analysis_state() ==
+ ImageAnalysisState::kNoAnimatedImages) {
+ return;
}
+
+ base::AutoReset<bool> auto_reset(&only_gather_animated_images_, true);
+ size_t prev_image_set_size = image_set_.size();
+ ImageGatheringProvider image_provider(this, op_rect);
+ filter->SnapshotWithImages(&image_provider);
+
+ DCHECK_GE(image_set_.size(), prev_image_set_size);
+ const bool has_animated_images = image_set_.size() > prev_image_set_size;
+ const_cast<PaintFilter*>(filter)->set_has_animated_images(
+ has_animated_images);
}
void AddImage(PaintImage paint_image,
@@ -335,7 +391,8 @@ class DiscardableImageGenerator {
// are animated. We defer decoding of images in record shaders to skia, but
// we still need to track animated images to invalidate and advance the
// animation in cc.
- bool add_image = !iterating_record_shaders_ || paint_image.ShouldAnimate();
+ bool add_image =
+ !only_gather_animated_images_ || paint_image.ShouldAnimate();
if (add_image) {
image_set_.emplace_back(
DrawImage(std::move(paint_image), src_irect, filter_quality, matrix),
@@ -348,7 +405,7 @@ class DiscardableImageGenerator {
std::vector<DiscardableImageMap::AnimatedImageMetadata>
animated_images_metadata_;
base::flat_map<PaintImage::Id, PaintImage::DecodingMode> decoding_mode_map_;
- bool iterating_record_shaders_ = false;
+ bool only_gather_animated_images_ = false;
// Statistics about the number of images and pixels that will require color
// conversion if the target color space is not sRGB.
diff --git a/chromium/cc/paint/discardable_image_map_unittest.cc b/chromium/cc/paint/discardable_image_map_unittest.cc
index 72906af6d90..72d608b2e35 100644
--- a/chromium/cc/paint/discardable_image_map_unittest.cc
+++ b/chromium/cc/paint/discardable_image_map_unittest.cc
@@ -756,9 +756,11 @@ TEST_F(DiscardableImageMapTest, CapturesImagesInPaintRecordShaders) {
display_list->EndPaintOfUnpaired(visible_rect);
display_list->Finalize();
- EXPECT_FALSE(flags.getShader()->has_animated_images());
+ EXPECT_EQ(flags.getShader()->image_analysis_state(),
+ ImageAnalysisState::kNoAnalysis);
display_list->GenerateDiscardableImagesMetadata();
- EXPECT_TRUE(flags.getShader()->has_animated_images());
+ EXPECT_EQ(flags.getShader()->image_analysis_state(),
+ ImageAnalysisState::kAnimatedImages);
const auto& image_map = display_list->discardable_image_map();
// The image rect is set to the rect for the DrawRectOp, and only animated
@@ -776,6 +778,75 @@ TEST_F(DiscardableImageMapTest, CapturesImagesInPaintRecordShaders) {
EXPECT_EQ(SkSize::Make(4.f, 4.f), draw_images[0].scale);
}
+TEST_F(DiscardableImageMapTest, CapturesImagesInPaintFilters) {
+ // Create the record to use in the filter.
+ auto filter_record = sk_make_sp<PaintOpBuffer>();
+
+ PaintImage static_image = CreateDiscardablePaintImage(gfx::Size(100, 100));
+ filter_record->push<DrawImageOp>(static_image, 0.f, 0.f, nullptr);
+
+ std::vector<FrameMetadata> frames = {
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(1)),
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(1))};
+ PaintImage animated_image = CreateAnimatedImage(gfx::Size(100, 100), frames);
+ filter_record->push<DrawImageOp>(animated_image, 0.f, 0.f, nullptr);
+
+ gfx::Rect visible_rect(500, 500);
+ scoped_refptr<DisplayItemList> display_list = new DisplayItemList();
+ display_list->StartPaint();
+ PaintFlags flags;
+ flags.setImageFilter(sk_make_sp<RecordPaintFilter>(
+ filter_record, SkRect::MakeWH(100.f, 100.f)));
+ display_list->push<DrawRectOp>(SkRect::MakeWH(200, 200), flags);
+ display_list->EndPaintOfUnpaired(visible_rect);
+ display_list->Finalize();
+
+ EXPECT_EQ(flags.getImageFilter()->image_analysis_state(),
+ ImageAnalysisState::kNoAnalysis);
+ display_list->GenerateDiscardableImagesMetadata();
+ EXPECT_EQ(flags.getImageFilter()->image_analysis_state(),
+ ImageAnalysisState::kAnimatedImages);
+ const auto& image_map = display_list->discardable_image_map();
+
+ // The image rect is set to the rect for the DrawRectOp, and only animated
+ // images in a filter are tracked.
+ std::vector<PositionScaleDrawImage> draw_images =
+ GetDiscardableImagesInRect(image_map, visible_rect);
+ std::vector<gfx::Rect> inset_rects = InsetImageRects(draw_images);
+ ASSERT_EQ(draw_images.size(), 1u);
+ EXPECT_EQ(draw_images[0].image, animated_image);
+ // The position of the image is the position of the DrawRectOp that uses the
+ // filter.
+ EXPECT_EQ(gfx::Rect(200, 200), inset_rects[0]);
+ // Images in a filter are decoded at the original size.
+ EXPECT_EQ(SkSize::Make(1.f, 1.f), draw_images[0].scale);
+}
+
+TEST_F(DiscardableImageMapTest, CapturesImagesInSaveLayers) {
+ PaintFlags flags;
+ PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
+ flags.setShader(PaintShader::MakeImage(image, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode, nullptr));
+
+ gfx::Rect visible_rect(500, 500);
+ scoped_refptr<DisplayItemList> display_list = new DisplayItemList();
+ display_list->StartPaint();
+ display_list->push<SaveLayerOp>(nullptr, &flags);
+ display_list->push<DrawColorOp>(SK_ColorBLUE, SkBlendMode::kSrc);
+ display_list->EndPaintOfUnpaired(visible_rect);
+ display_list->Finalize();
+
+ display_list->GenerateDiscardableImagesMetadata();
+ const auto& image_map = display_list->discardable_image_map();
+ std::vector<PositionScaleDrawImage> draw_images =
+ GetDiscardableImagesInRect(image_map, visible_rect);
+ std::vector<gfx::Rect> inset_rects = InsetImageRects(draw_images);
+ ASSERT_EQ(draw_images.size(), 1u);
+ EXPECT_EQ(draw_images[0].image, image);
+ EXPECT_EQ(gfx::Rect(500, 500), inset_rects[0]);
+ EXPECT_EQ(SkSize::Make(1.f, 1.f), draw_images[0].scale);
+}
+
TEST_F(DiscardableImageMapTest, EmbeddedShaderWithAnimatedImages) {
// Create the record with animated image to use in the shader.
SkRect tile = SkRect::MakeWH(100, 100);
@@ -806,8 +877,10 @@ TEST_F(DiscardableImageMapTest, EmbeddedShaderWithAnimatedImages) {
display_list->EndPaintOfUnpaired(visible_rect);
display_list->Finalize();
display_list->GenerateDiscardableImagesMetadata();
- EXPECT_TRUE(shader_with_image->has_animated_images());
- EXPECT_TRUE(shader_with_shader_with_image->has_animated_images());
+ EXPECT_EQ(shader_with_image->image_analysis_state(),
+ ImageAnalysisState::kAnimatedImages);
+ EXPECT_EQ(shader_with_shader_with_image->image_analysis_state(),
+ ImageAnalysisState::kAnimatedImages);
}
TEST_F(DiscardableImageMapTest, DecodingModeHintsBasic) {
diff --git a/chromium/cc/paint/display_item_list.cc b/chromium/cc/paint/display_item_list.cc
index d88cfa7aef3..21e5044b906 100644
--- a/chromium/cc/paint/display_item_list.cc
+++ b/chromium/cc/paint/display_item_list.cc
@@ -8,7 +8,6 @@
#include <string>
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/base/math_util.h"
@@ -56,21 +55,16 @@ void DisplayItemList::Raster(SkCanvas* canvas,
paint_op_buffer_.Playback(canvas, PlaybackParams(image_provider), &offsets);
}
-void DisplayItemList::GrowCurrentBeginItemVisualRect(
- const gfx::Rect& visual_rect) {
- DCHECK(usage_hint_ == kTopLevelDisplayItemList);
- if (!begin_paired_indices_.empty())
- visual_rects_[begin_paired_indices_.back().first].Union(visual_rect);
-}
-
void DisplayItemList::Finalize() {
TRACE_EVENT0("cc", "DisplayItemList::Finalize");
+#if DCHECK_IS_ON()
// If this fails a call to StartPaint() was not ended.
- DCHECK(!in_painting_);
+ DCHECK(!IsPainting());
// If this fails we had more calls to EndPaintOfPairedBegin() than
// to EndPaintOfPairedEnd().
- DCHECK_EQ(0, in_paired_begin_count_);
+ DCHECK(begin_paired_indices_.empty());
DCHECK_EQ(visual_rects_.size(), offsets_.size());
+#endif
if (usage_hint_ == kTopLevelDisplayItemList) {
rtree_.Build(visual_rects_,
@@ -120,8 +114,12 @@ DisplayItemList::CreateTracedValue(bool include_items) const {
state->BeginArray("items");
PlaybackParams params(nullptr, SkMatrix::I());
+ const auto& bounds = rtree_.GetAllBoundsForTracing();
+ size_t i = 0;
for (const PaintOp* op : PaintOpBuffer::Iterator(&paint_op_buffer_)) {
state->BeginDictionary();
+ state->SetString("name", PaintOpTypeToString(op->GetType()));
+ MathUtil::AddToTracedValue("visual_rect", bounds[i++], state.get());
SkPictureRecorder recorder;
SkCanvas* canvas =
@@ -129,9 +127,11 @@ DisplayItemList::CreateTracedValue(bool include_items) const {
op->Raster(canvas, params);
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
- std::string b64_picture;
- PictureDebugUtil::SerializeAsBase64(picture.get(), &b64_picture);
- state->SetString("skp64", b64_picture);
+ if (picture->approximateOpCount()) {
+ std::string b64_picture;
+ PictureDebugUtil::SerializeAsBase64(picture.get(), &b64_picture);
+ state->SetString("skp64", b64_picture);
+ }
state->EndDictionary();
}
@@ -164,8 +164,10 @@ void DisplayItemList::GenerateDiscardableImagesMetadata() {
}
void DisplayItemList::Reset() {
- DCHECK(!in_painting_);
- DCHECK_EQ(0, in_paired_begin_count_);
+#if DCHECK_IS_ON()
+ DCHECK(!IsPainting());
+ DCHECK(begin_paired_indices_.empty());
+#endif
rtree_.Reset();
image_map_.Reset();
@@ -176,9 +178,6 @@ void DisplayItemList::Reset() {
offsets_.shrink_to_fit();
begin_paired_indices_.clear();
begin_paired_indices_.shrink_to_fit();
- current_range_start_ = 0;
- in_paired_begin_count_ = 0;
- in_painting_ = false;
}
sk_sp<PaintRecord> DisplayItemList::ReleaseAsRecord() {
diff --git a/chromium/cc/paint/display_item_list.h b/chromium/cc/paint/display_item_list.h
index c3e50a3ed18..0ade2b179f3 100644
--- a/chromium/cc/paint/display_item_list.h
+++ b/chromium/cc/paint/display_item_list.h
@@ -59,26 +59,42 @@ class CC_PAINT_EXPORT DisplayItemList
void Raster(SkCanvas* canvas, ImageProvider* image_provider = nullptr) const;
- // TODO(vmpstr): This is only used to keep track of debugging info, so we can
- // probably remove it? But it would be nice to delimit painting in a block
- // somehow (RAII object maybe).
void StartPaint() {
- DCHECK(!in_painting_);
- in_painting_ = true;
+#if DCHECK_IS_ON()
+ DCHECK(!IsPainting());
+ current_range_start_ = paint_op_buffer_.size();
+#endif
}
// Push functions construct a new op on the paint op buffer, while maintaining
// bookkeeping information. Must be called after invoking StartPaint().
+ // Returns the id (which is an opaque value) of the operation that can be used
+ // in UpdateSaveLayerBounds().
template <typename T, typename... Args>
- void push(Args&&... args) {
- DCHECK(in_painting_);
+ size_t push(Args&&... args) {
+#if DCHECK_IS_ON()
+ DCHECK(IsPainting());
+#endif
+ size_t offset = paint_op_buffer_.next_op_offset();
if (usage_hint_ == kTopLevelDisplayItemList)
- offsets_.push_back(paint_op_buffer_.next_op_offset());
+ offsets_.push_back(offset);
paint_op_buffer_.push<T>(std::forward<Args>(args)...);
+ return offset;
+ }
+
+ // Called by blink::PaintChunksToCcLayer when an effect ends, to update the
+ // bounds of a SaveLayer[Alpha]Op which was emitted when the effect started.
+ // This is needed because blink doesn't know the bounds when an effect starts.
+ // Don't add other mutation methods like this if there is better alternative.
+ void UpdateSaveLayerBounds(size_t id, const SkRect& bounds) {
+ paint_op_buffer_.UpdateSaveLayerBounds(id, bounds);
}
void EndPaintOfUnpaired(const gfx::Rect& visual_rect) {
- in_painting_ = false;
+#if DCHECK_IS_ON()
+ DCHECK(IsPainting());
+ current_range_start_ = kNotPainting;
+#endif
if (usage_hint_ == kToBeReleasedAsPaintOpBuffer)
return;
@@ -88,26 +104,32 @@ class CC_PAINT_EXPORT DisplayItemList
}
void EndPaintOfPairedBegin(const gfx::Rect& visual_rect = gfx::Rect()) {
- in_painting_ = false;
+#if DCHECK_IS_ON()
+ DCHECK(IsPainting());
+ DCHECK_LT(current_range_start_, paint_op_buffer_.size());
+ current_range_start_ = kNotPainting;
+#endif
if (usage_hint_ == kToBeReleasedAsPaintOpBuffer)
return;
- DCHECK_NE(visual_rects_.size(), paint_op_buffer_.size());
+
+ DCHECK_LT(visual_rects_.size(), paint_op_buffer_.size());
size_t count = paint_op_buffer_.size() - visual_rects_.size();
for (size_t i = 0; i < count; ++i)
visual_rects_.push_back(visual_rect);
begin_paired_indices_.push_back(
std::make_pair(visual_rects_.size() - 1, count));
-
- in_paired_begin_count_++;
}
void EndPaintOfPairedEnd() {
- in_painting_ = false;
+#if DCHECK_IS_ON()
+ DCHECK(IsPainting());
+ DCHECK_LT(current_range_start_, paint_op_buffer_.size());
+ current_range_start_ = kNotPainting;
+#endif
if (usage_hint_ == kToBeReleasedAsPaintOpBuffer)
return;
- DCHECK_NE(current_range_start_, paint_op_buffer_.size());
- DCHECK(in_paired_begin_count_);
+ DCHECK(begin_paired_indices_.size());
size_t last_begin_index = begin_paired_indices_.back().first;
size_t last_begin_count = begin_paired_indices_.back().second;
DCHECK_GT(last_begin_count, 0u);
@@ -131,8 +153,6 @@ class CC_PAINT_EXPORT DisplayItemList
// The block that ended needs to be included in the bounds of the enclosing
// block.
GrowCurrentBeginItemVisualRect(visual_rect);
-
- in_paired_begin_count_--;
}
// Called after all items are appended, to process the items.
@@ -142,7 +162,7 @@ class CC_PAINT_EXPORT DisplayItemList
bool HasNonAAPaint() const { return paint_op_buffer_.HasNonAAPaint(); }
// This gives the total number of PaintOps.
- size_t op_count() const { return paint_op_buffer_.size(); }
+ size_t TotalOpCount() const { return paint_op_buffer_.total_op_count(); }
size_t BytesUsed() const;
const DiscardableImageMap& discardable_image_map() const {
@@ -183,7 +203,11 @@ class CC_PAINT_EXPORT DisplayItemList
// If we're currently within a paired display item block, unions the
// given visual rect with the begin display item's visual rect.
- void GrowCurrentBeginItemVisualRect(const gfx::Rect& visual_rect);
+ void GrowCurrentBeginItemVisualRect(const gfx::Rect& visual_rect) {
+ DCHECK_EQ(usage_hint_, kTopLevelDisplayItemList);
+ if (!begin_paired_indices_.empty())
+ visual_rects_[begin_paired_indices_.back().first].Union(visual_rect);
+ }
// RTree stores indices into the paint op buffer.
// TODO(vmpstr): Update the rtree to store offsets instead.
@@ -202,15 +226,14 @@ class CC_PAINT_EXPORT DisplayItemList
// counts refer to the number of visual rects in that begin sequence that end
// with the index.
std::vector<std::pair<size_t, size_t>> begin_paired_indices_;
+
+#if DCHECK_IS_ON()
// While recording a range of ops, this is the position in the PaintOpBuffer
// where the recording started.
- size_t current_range_start_ = 0;
- // For debugging, tracks the number of currently nested visual rects being
- // added.
- int in_paired_begin_count_ = 0;
- // For debugging, tracks if we're painting a visual rect range, to prevent
- // nesting.
- bool in_painting_ = false;
+ bool IsPainting() const { return current_range_start_ != kNotPainting; }
+ const size_t kNotPainting = static_cast<size_t>(-1);
+ size_t current_range_start_ = kNotPainting;
+#endif
UsageHint usage_hint_;
diff --git a/chromium/cc/paint/display_item_list_unittest.cc b/chromium/cc/paint/display_item_list_unittest.cc
index 43215b4a21e..5bcca13606d 100644
--- a/chromium/cc/paint/display_item_list_unittest.cc
+++ b/chromium/cc/paint/display_item_list_unittest.cc
@@ -8,7 +8,6 @@
#include <vector>
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/paint/filter_operation.h"
@@ -64,6 +63,20 @@ bool CompareN32Pixels(void* actual_pixels,
} // namespace
+#define EXPECT_TRACED_RECT(x, y, width, height, rect_list) \
+ do { \
+ ASSERT_EQ(4u, rect_list->GetSize()); \
+ double d; \
+ EXPECT_TRUE((rect_list)->GetDouble(0, &d)); \
+ EXPECT_EQ(x, d); \
+ EXPECT_TRUE((rect_list)->GetDouble(1, &d)); \
+ EXPECT_EQ(y, d); \
+ EXPECT_TRUE((rect_list)->GetDouble(2, &d)); \
+ EXPECT_EQ(width, d); \
+ EXPECT_TRUE((rect_list)->GetDouble(3, &d)); \
+ EXPECT_EQ(height, d); \
+ } while (false)
+
TEST(DisplayItemListTest, SingleUnpairedRange) {
gfx::Rect layer_rect(100, 100);
PaintFlags blue_flags;
@@ -114,7 +127,7 @@ TEST(DisplayItemListTest, EmptyUnpairedRangeDoesNotAddVisualRect) {
list->EndPaintOfUnpaired(layer_rect);
}
// No ops.
- EXPECT_EQ(0u, list->op_count());
+ EXPECT_EQ(0u, list->TotalOpCount());
{
list->StartPaint();
@@ -123,7 +136,7 @@ TEST(DisplayItemListTest, EmptyUnpairedRangeDoesNotAddVisualRect) {
list->EndPaintOfUnpaired(layer_rect);
}
// Two ops.
- EXPECT_EQ(2u, list->op_count());
+ EXPECT_EQ(2u, list->TotalOpCount());
}
TEST(DisplayItemListTest, ClipPairedRange) {
@@ -399,15 +412,10 @@ TEST(DisplayItemListTest, AsValueWithNoOps) {
// The real contents of the traced value is in here.
{
const base::ListValue* list;
- double d;
// The layer_rect field is present by empty.
ASSERT_TRUE(params_dict->GetList("layer_rect", &list));
- ASSERT_EQ(4u, list->GetSize());
- EXPECT_TRUE(list->GetDouble(0, &d) && d == 0) << d;
- EXPECT_TRUE(list->GetDouble(1, &d) && d == 0) << d;
- EXPECT_TRUE(list->GetDouble(2, &d) && d == 0) << d;
- EXPECT_TRUE(list->GetDouble(3, &d) && d == 0) << d;
+ EXPECT_TRACED_RECT(0, 0, 0, 0, list);
// The items list is there but empty.
ASSERT_TRUE(params_dict->GetList("items", &list));
@@ -426,15 +434,10 @@ TEST(DisplayItemListTest, AsValueWithNoOps) {
// The real contents of the traced value is in here.
{
const base::ListValue* list;
- double d;
// The layer_rect field is present by empty.
ASSERT_TRUE(params_dict->GetList("layer_rect", &list));
- ASSERT_EQ(4u, list->GetSize());
- EXPECT_TRUE(list->GetDouble(0, &d) && d == 0) << d;
- EXPECT_TRUE(list->GetDouble(1, &d) && d == 0) << d;
- EXPECT_TRUE(list->GetDouble(2, &d) && d == 0) << d;
- EXPECT_TRUE(list->GetDouble(3, &d) && d == 0) << d;
+ EXPECT_TRACED_RECT(0, 0, 0, 0, list);
// The items list is not there since we asked for no ops.
ASSERT_FALSE(params_dict->GetList("items", &list));
@@ -463,10 +466,11 @@ TEST(DisplayItemListTest, AsValueWithOps) {
PaintFlags red_paint;
red_paint.setColor(SK_ColorRED);
- list->push<SaveOp>();
+ list->push<SaveLayerOp>(nullptr, &red_paint);
list->push<TranslateOp>(static_cast<float>(offset.x()),
static_cast<float>(offset.y()));
list->push<DrawRectOp>(SkRect::MakeWH(4, 4), red_paint);
+ list->push<RestoreOp>();
list->EndPaintOfUnpaired(bounds);
}
@@ -490,28 +494,35 @@ TEST(DisplayItemListTest, AsValueWithOps) {
// The real contents of the traced value is in here.
{
- const base::ListValue* list;
- double d;
-
+ const base::ListValue* layer_rect;
// The layer_rect field is present and has the bounds of the rtree.
- ASSERT_TRUE(params_dict->GetList("layer_rect", &list));
- ASSERT_EQ(4u, list->GetSize());
- EXPECT_TRUE(list->GetDouble(0, &d) && d == 2) << d;
- EXPECT_TRUE(list->GetDouble(1, &d) && d == 3) << d;
- EXPECT_TRUE(list->GetDouble(2, &d) && d == 8) << d;
- EXPECT_TRUE(list->GetDouble(3, &d) && d == 9) << d;
+ ASSERT_TRUE(params_dict->GetList("layer_rect", &layer_rect));
+ EXPECT_TRACED_RECT(2, 3, 8, 9, layer_rect);
// The items list has 3 things in it since we built 3 visual rects.
- ASSERT_TRUE(params_dict->GetList("items", &list));
- EXPECT_EQ(6u, list->GetSize());
+ const base::ListValue* items;
+ ASSERT_TRUE(params_dict->GetList("items", &items));
+ ASSERT_EQ(7u, items->GetSize());
- for (int i = 0; i < 6; ++i) {
+ const char* expected_names[] = {"Save", "Concat", "SaveLayer",
+ "Translate", "DrawRect", "Restore",
+ "Restore"};
+ bool expected_has_skp[] = {false, true, true, true, true, false, false};
+
+ for (int i = 0; i < 7; ++i) {
const base::DictionaryValue* item_dict;
+ ASSERT_TRUE(items->GetDictionary(i, &item_dict));
+
+ const base::ListValue* visual_rect;
+ ASSERT_TRUE(item_dict->GetList("visual_rect", &visual_rect));
+ EXPECT_TRACED_RECT(2, 3, 8, 9, visual_rect);
- ASSERT_TRUE(list->GetDictionary(i, &item_dict));
+ std::string name;
+ EXPECT_TRUE(item_dict->GetString("name", &name));
+ EXPECT_EQ(expected_names[i], name);
- // The SkPicture for each item exists.
- EXPECT_TRUE(
+ EXPECT_EQ(
+ expected_has_skp[i],
item_dict->GetString("skp64", static_cast<std::string*>(nullptr)));
}
}
@@ -528,15 +539,9 @@ TEST(DisplayItemListTest, AsValueWithOps) {
// The real contents of the traced value is in here.
{
const base::ListValue* list;
- double d;
-
// The layer_rect field is present and has the bounds of the rtree.
ASSERT_TRUE(params_dict->GetList("layer_rect", &list));
- ASSERT_EQ(4u, list->GetSize());
- EXPECT_TRUE(list->GetDouble(0, &d) && d == 2) << d;
- EXPECT_TRUE(list->GetDouble(1, &d) && d == 3) << d;
- EXPECT_TRUE(list->GetDouble(2, &d) && d == 8) << d;
- EXPECT_TRUE(list->GetDouble(3, &d) && d == 9) << d;
+ EXPECT_TRACED_RECT(2, 3, 8, 9, list);
// The items list is not present since we asked for no ops.
ASSERT_FALSE(params_dict->GetList("items", &list));
@@ -546,7 +551,7 @@ TEST(DisplayItemListTest, AsValueWithOps) {
TEST(DisplayItemListTest, SizeEmpty) {
auto list = base::MakeRefCounted<DisplayItemList>();
- EXPECT_EQ(0u, list->op_count());
+ EXPECT_EQ(0u, list->TotalOpCount());
}
TEST(DisplayItemListTest, SizeOne) {
@@ -557,7 +562,7 @@ TEST(DisplayItemListTest, SizeOne) {
list->push<DrawRectOp>(gfx::RectToSkRect(drawing_bounds), PaintFlags());
list->EndPaintOfUnpaired(drawing_bounds);
}
- EXPECT_EQ(1u, list->op_count());
+ EXPECT_EQ(1u, list->TotalOpCount());
}
TEST(DisplayItemListTest, SizeMultiple) {
@@ -575,7 +580,7 @@ TEST(DisplayItemListTest, SizeMultiple) {
list->push<RestoreOp>();
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(3u, list->op_count());
+ EXPECT_EQ(3u, list->TotalOpCount());
}
TEST(DisplayItemListTest, AppendVisualRectSimple) {
@@ -590,7 +595,7 @@ TEST(DisplayItemListTest, AppendVisualRectSimple) {
list->EndPaintOfUnpaired(drawing_bounds);
}
- EXPECT_EQ(1u, list->op_count());
+ EXPECT_EQ(1u, list->TotalOpCount());
EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
}
@@ -613,7 +618,7 @@ TEST(DisplayItemListTest, AppendVisualRectEmptyBlock) {
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(3u, list->op_count());
+ EXPECT_EQ(3u, list->TotalOpCount());
EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(0));
EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(1));
EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(2));
@@ -650,7 +655,7 @@ TEST(DisplayItemListTest, AppendVisualRectEmptyBlockContainingEmptyBlock) {
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(5u, list->op_count());
+ EXPECT_EQ(5u, list->TotalOpCount());
EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(0));
EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(1));
EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(2));
@@ -685,7 +690,7 @@ TEST(DisplayItemListTest, AppendVisualRectBlockContainingDrawing) {
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(4u, list->op_count());
+ EXPECT_EQ(4u, list->TotalOpCount());
EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(1));
EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(2));
@@ -719,7 +724,7 @@ TEST(DisplayItemListTest, AppendVisualRectBlockContainingEscapedDrawing) {
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(4u, list->op_count());
+ EXPECT_EQ(4u, list->TotalOpCount());
EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(1));
EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(2));
@@ -762,7 +767,7 @@ TEST(DisplayItemListTest,
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(5u, list->op_count());
+ EXPECT_EQ(5u, list->TotalOpCount());
EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(0));
EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(1));
EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(2));
@@ -818,7 +823,7 @@ TEST(DisplayItemListTest, AppendVisualRectTwoBlocksTwoDrawings) {
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(8u, list->op_count());
+ EXPECT_EQ(8u, list->TotalOpCount());
gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
merged_drawing_bounds.Union(drawing_b_bounds);
EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
@@ -881,7 +886,7 @@ TEST(DisplayItemListTest,
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(8u, list->op_count());
+ EXPECT_EQ(8u, list->TotalOpCount());
gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
merged_drawing_bounds.Union(drawing_b_bounds);
EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
@@ -944,7 +949,7 @@ TEST(DisplayItemListTest,
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(8u, list->op_count());
+ EXPECT_EQ(8u, list->TotalOpCount());
gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
merged_drawing_bounds.Union(drawing_b_bounds);
EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
@@ -1007,7 +1012,7 @@ TEST(DisplayItemListTest,
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(8u, list->op_count());
+ EXPECT_EQ(8u, list->TotalOpCount());
gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
merged_drawing_bounds.Union(drawing_b_bounds);
EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
@@ -1045,10 +1050,31 @@ TEST(DisplayItemListTest, VisualRectForPairsEnclosingEmptyPainting) {
list->EndPaintOfPairedEnd();
}
- EXPECT_EQ(3u, list->op_count());
+ EXPECT_EQ(3u, list->TotalOpCount());
EXPECT_RECT_EQ(visual_rect, list->VisualRectForTesting(0));
EXPECT_RECT_EQ(visual_rect, list->VisualRectForTesting(1));
EXPECT_RECT_EQ(visual_rect, list->VisualRectForTesting(2));
}
+TEST(DisplayItemListTest, TotalOpCount) {
+ auto list = base::MakeRefCounted<DisplayItemList>();
+ auto sub_list = base::MakeRefCounted<DisplayItemList>();
+
+ sub_list->StartPaint();
+ sub_list->push<SaveOp>();
+ sub_list->push<TranslateOp>(10.f, 20.f);
+ sub_list->push<DrawRectOp>(SkRect::MakeWH(10, 20), PaintFlags());
+ sub_list->push<RestoreOp>();
+ sub_list->EndPaintOfUnpaired(gfx::Rect());
+ EXPECT_EQ(4u, sub_list->TotalOpCount());
+
+ list->StartPaint();
+ list->push<SaveOp>();
+ list->push<TranslateOp>(10.f, 20.f);
+ list->push<DrawRecordOp>(sub_list->ReleaseAsRecord());
+ list->push<RestoreOp>();
+ list->EndPaintOfUnpaired(gfx::Rect());
+ EXPECT_EQ(8u, list->TotalOpCount());
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/image_analysis_state.h b/chromium/cc/paint/image_analysis_state.h
new file mode 100644
index 00000000000..ebf085dcc35
--- /dev/null
+++ b/chromium/cc/paint/image_analysis_state.h
@@ -0,0 +1,18 @@
+// 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_PAINT_IMAGE_ANALYSIS_STATE_H_
+#define CC_PAINT_IMAGE_ANALYSIS_STATE_H_
+
+namespace cc {
+
+enum class ImageAnalysisState {
+ kNoAnalysis,
+ kAnimatedImages,
+ kNoAnimatedImages,
+};
+
+} // namespace cc
+
+#endif // CC_PAINT_IMAGE_ANALYSIS_STATE_H_
diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc
index 82be5625783..c0f6d025f2c 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.cc
+++ b/chromium/cc/paint/image_transfer_cache_entry.cc
@@ -15,7 +15,15 @@ namespace cc {
ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
const SkPixmap* pixmap,
const SkColorSpace* target_color_space)
- : id_(s_next_id_.GetNext()), pixmap_(pixmap) {
+ : id_(s_next_id_.GetNext()),
+ pixmap_(pixmap),
+ target_color_space_(target_color_space) {
+ size_t target_color_space_size =
+ target_color_space ? target_color_space->writeToMemory(nullptr) : 0u;
+ size_t pixmap_color_space_size =
+ pixmap_->colorSpace() ? pixmap_->colorSpace()->writeToMemory(nullptr)
+ : 0u;
+
// Compute and cache the size of the data.
// We write the following:
// - Image color type (uint32_t)
@@ -30,9 +38,11 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
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);
size_ = safe_size.ValueOrDie();
- // TODO(ericrk): Handle colorspace.
}
+
ClientImageTransferCacheEntry::~ClientImageTransferCacheEntry() = default;
// static
@@ -55,9 +65,10 @@ bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const {
writer.Write(pixmap_->height());
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.WriteData(pixmap_size, pixmap_->addr());
- // TODO(ericrk): Handle colorspace.
-
if (writer.size() != data.size())
return false;
@@ -76,8 +87,9 @@ size_t ServiceImageTransferCacheEntry::CachedSize() const {
return size_;
}
-bool ServiceImageTransferCacheEntry::Deserialize(GrContext* context,
- base::span<uint8_t> data) {
+bool ServiceImageTransferCacheEntry::Deserialize(
+ GrContext* context,
+ base::span<const uint8_t> data) {
PaintOpReader reader(data.data(), data.size(), nullptr);
SkColorType color_type;
reader.Read(&color_type);
@@ -88,12 +100,18 @@ bool ServiceImageTransferCacheEntry::Deserialize(GrContext* context,
size_t pixel_size;
reader.ReadSize(&pixel_size);
size_ = data.size();
+ sk_sp<SkColorSpace> pixmap_color_space;
+ reader.Read(&pixmap_color_space);
+ sk_sp<SkColorSpace> target_color_space;
+ reader.Read(&target_color_space);
+
if (!reader.valid())
return false;
- // TODO(ericrk): Handle colorspace.
- SkImageInfo image_info =
- SkImageInfo::Make(width, height, color_type, kPremul_SkAlphaType);
+ SkImageInfo image_info = SkImageInfo::Make(
+ width, height, color_type, kPremul_SkAlphaType, pixmap_color_space);
+ if (image_info.computeMinByteSize() > pixel_size)
+ return false;
const volatile void* pixel_data = reader.ExtractReadableMemory(pixel_size);
if (!reader.valid())
return false;
@@ -106,16 +124,39 @@ bool ServiceImageTransferCacheEntry::Deserialize(GrContext* context,
// Depending on whether the pixmap will fit in a GPU texture, either create
// a software or GPU SkImage.
- uint32_t max_size = context->caps()->maxTextureSize();
+ uint32_t max_size = context->maxTextureSize();
bool fits_on_gpu = width <= max_size && height <= max_size;
if (fits_on_gpu) {
sk_sp<SkImage> image = SkImage::MakeFromRaster(pixmap, nullptr, nullptr);
- DCHECK(image);
+ 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);
+ }
} else {
- image_ = SkImage::MakeRasterCopy(pixmap);
+ 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);
+ // If color space conversion is a noop, use original data.
+ if (image_ == original)
+ image_ = SkImage::MakeRasterCopy(pixmap);
+ } else {
+ // No color conversion to do, use original data.
+ image_ = SkImage::MakeRasterCopy(pixmap);
+ }
}
+ // TODO(enne): consider adding in the DeleteSkImageAndPreventCaching
+ // optimization from GpuImageDecodeCache where we forcefully remove the
+ // intermediate from Skia's cache.
return image_;
}
diff --git a/chromium/cc/paint/image_transfer_cache_entry.h b/chromium/cc/paint/image_transfer_cache_entry.h
index a941c193e5d..fd3937d0926 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.h
+++ b/chromium/cc/paint/image_transfer_cache_entry.h
@@ -37,6 +37,7 @@ class CC_PAINT_EXPORT ClientImageTransferCacheEntry
private:
uint32_t id_;
const SkPixmap* const pixmap_;
+ const SkColorSpace* const target_color_space_;
size_t size_ = 0;
static base::AtomicSequenceNumber s_next_id_;
};
@@ -53,7 +54,7 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry
// ServiceTransferCacheEntry implementation:
size_t CachedSize() const final;
- bool Deserialize(GrContext* context, base::span<uint8_t> data) final;
+ bool Deserialize(GrContext* context, base::span<const uint8_t> data) final;
void set_image_for_testing(sk_sp<SkImage> image) {
image_ = std::move(image);
diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc
index 824e4c7d33e..6850d6f9ad9 100644
--- a/chromium/cc/paint/oop_pixeltest.cc
+++ b/chromium/cc/paint/oop_pixeltest.cc
@@ -10,9 +10,12 @@
#include "cc/base/region.h"
#include "cc/layers/recording_source.h"
#include "cc/paint/display_item_list.h"
+#include "cc/paint/paint_image_builder.h"
+#include "cc/raster/playback_image_provider.h"
#include "cc/raster/raster_source.h"
#include "cc/test/pixel_test_utils.h"
#include "cc/test/test_in_process_context_provider.h"
+#include "cc/tiles/gpu_image_decode_cache.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/raster_implementation_gles.h"
@@ -44,22 +47,6 @@ scoped_refptr<DisplayItemList> MakeNoopDisplayItemList() {
return display_item_list;
}
-class NoOpImageProvider : public ImageProvider {
- public:
- ~NoOpImageProvider() override = default;
-
- ScopedDecodedDrawImage GetDecodedDrawImage(
- const DrawImage& draw_image) override {
- SkBitmap bitmap;
- bitmap.allocPixelsFlags(SkImageInfo::MakeN32Premul(10, 10),
- SkBitmap::kZeroPixels_AllocFlag);
- sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
- return ScopedDecodedDrawImage(DecodedDrawImage(image, SkSize::Make(10, 10),
- SkSize::Make(1, 1),
- kLow_SkFilterQuality, true));
- }
-};
-
class OopPixelTest : public testing::Test {
public:
void SetUp() override {
@@ -72,54 +59,31 @@ class OopPixelTest : public testing::Test {
switches::kEnableOOPRasterization);
}
- // Setup a GL context for reading back pixels.
- bool is_offscreen = true;
- gpu::ContextCreationAttribs attribs;
- attribs.alpha_size = -1;
- attribs.depth_size = 24;
- attribs.stencil_size = 8;
- attribs.samples = 0;
- attribs.sample_buffers = 0;
- attribs.fail_if_major_perf_caveat = false;
- attribs.bind_generates_resource = false;
-
- context_ = gpu::GLInProcessContext::CreateWithoutInit();
- auto result = context_->Initialize(
- nullptr, nullptr, is_offscreen, gpu::kNullSurfaceHandle, nullptr,
- attribs, gpu::SharedMemoryLimits(), &gpu_memory_buffer_manager_,
- &image_factory_, nullptr, base::ThreadTaskRunnerHandle::Get());
-
- ASSERT_EQ(result, gpu::ContextResult::kSuccess);
-
- // Setup a second context with OOP rasterization enabled and a
- // RasterInterface on top of it.
- attribs.enable_oop_rasterization = true;
-
- raster_context_ = gpu::GLInProcessContext::CreateWithoutInit();
- result = raster_context_->Initialize(
- nullptr, nullptr, is_offscreen, gpu::kNullSurfaceHandle, nullptr,
- attribs, gpu::SharedMemoryLimits(), &gpu_memory_buffer_manager_,
- &image_factory_, nullptr, base::ThreadTaskRunnerHandle::Get());
- ASSERT_EQ(result, gpu::ContextResult::kSuccess);
- ASSERT_TRUE(raster_context_->GetCapabilities().supports_oop_raster);
- raster_implementation_ =
- std::make_unique<gpu::raster::RasterImplementationGLES>(
- raster_context_->GetImplementation(),
- raster_context_->GetImplementation(),
- raster_context_->GetCapabilities());
+ context_provider_ =
+ base::MakeRefCounted<TestInProcessContextProvider>(nullptr, true);
+ int max_texture_size =
+ context_provider_->ContextCapabilities().max_texture_size;
+ oop_image_cache_.reset(new GpuImageDecodeCache(
+ context_provider_.get(), true, kRGBA_8888_SkColorType, kWorkingSetSize,
+ max_texture_size));
+ gpu_image_cache_.reset(new GpuImageDecodeCache(
+ context_provider_.get(), false, kRGBA_8888_SkColorType, kWorkingSetSize,
+ max_texture_size));
}
- void TearDown() override {
- raster_implementation_.reset();
- raster_context_.reset();
- context_.reset();
- }
+ class RasterOptions {
+ public:
+ RasterOptions() = default;
+ explicit RasterOptions(const gfx::Size& playback_size) {
+ resource_size = playback_size;
+ content_size = resource_size;
+ full_raster_rect = gfx::Rect(playback_size);
+ playback_rect = gfx::Rect(playback_size);
+ }
- struct RasterOptions {
SkColor background_color = SK_ColorBLACK;
int msaa_sample_count = 0;
bool use_lcd_text = false;
- bool use_distance_field_text = false;
SkColorType color_type = kRGBA_8888_SkColorType;
gfx::Size resource_size;
gfx::Size content_size;
@@ -131,67 +95,69 @@ class OopPixelTest : public testing::Test {
bool requires_clear = false;
bool preclear = false;
SkColor preclear_color;
+ ImageDecodeCache* image_cache = nullptr;
};
SkBitmap Raster(scoped_refptr<DisplayItemList> display_item_list,
const gfx::Size& playback_size) {
- RasterOptions options;
- options.resource_size = playback_size;
- options.content_size = options.resource_size;
- options.full_raster_rect = gfx::Rect(playback_size);
- options.playback_rect = gfx::Rect(playback_size);
+ RasterOptions options(playback_size);
return Raster(display_item_list, options);
}
SkBitmap Raster(scoped_refptr<DisplayItemList> display_item_list,
const RasterOptions& options) {
- gpu::gles2::GLES2Interface* gl = context_->GetImplementation();
+ TestInProcessContextProvider::ScopedRasterContextLock lock(
+ context_provider_.get());
+
+ PlaybackImageProvider image_provider(oop_image_cache_.get(),
+ options.color_space,
+ PlaybackImageProvider::Settings());
+
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
int width = options.resource_size.width();
int height = options.resource_size.height();
// Create and allocate a texture on the raster interface.
GLuint raster_texture_id;
- raster_implementation_->GenTextures(1, &raster_texture_id);
- raster_implementation_->BindTexture(GL_TEXTURE_2D, raster_texture_id);
- raster_implementation_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
- 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- raster_implementation_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_LINEAR);
-
- EXPECT_EQ(raster_implementation_->GetError(),
+ auto* raster_implementation = 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->TexParameteri(raster_texture_id,
+ GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ EXPECT_EQ(raster_implementation->GetError(),
static_cast<unsigned>(GL_NO_ERROR));
RasterColorSpace color_space(options.color_space, ++color_space_id_);
if (options.preclear) {
- raster_implementation_->BeginRasterCHROMIUM(
+ raster_implementation->BeginRasterCHROMIUM(
raster_texture_id, options.preclear_color, options.msaa_sample_count,
- options.use_lcd_text, options.use_distance_field_text,
- options.color_type, color_space);
- raster_implementation_->EndRasterCHROMIUM();
+ options.use_lcd_text, options.color_type, color_space);
+ raster_implementation->EndRasterCHROMIUM();
}
// "Out of process" raster! \o/
- raster_implementation_->BeginRasterCHROMIUM(
+ raster_implementation->BeginRasterCHROMIUM(
raster_texture_id, options.background_color, options.msaa_sample_count,
- options.use_lcd_text, options.use_distance_field_text,
- options.color_type, color_space);
- raster_implementation_->RasterCHROMIUM(
- display_item_list.get(), &image_provider_, options.content_size,
+ options.use_lcd_text, options.color_type, color_space);
+ 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);
- raster_implementation_->EndRasterCHROMIUM();
+ 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_->GenMailboxCHROMIUM(mailbox.name);
- raster_implementation_->ProduceTextureDirectCHROMIUM(raster_texture_id,
- mailbox.name);
- raster_implementation_->OrderingBarrierCHROMIUM();
+ raster_implementation->GenMailbox(mailbox.name);
+ raster_implementation->ProduceTextureDirect(raster_texture_id,
+ mailbox.name);
+ raster_implementation->OrderingBarrierCHROMIUM();
- EXPECT_EQ(raster_implementation_->GetError(),
+ EXPECT_EQ(raster_implementation->GetError(),
static_cast<unsigned>(GL_NO_ERROR));
// Import the texture in gl, create an fbo and bind the texture to it.
@@ -211,7 +177,7 @@ class OopPixelTest : public testing::Test {
gl->DeleteFramebuffers(1, &fbo_id);
gl->OrderingBarrierCHROMIUM();
- raster_implementation_->DeleteTextures(1, &raster_texture_id);
+ raster_implementation->DeleteTextures(1, &raster_texture_id);
// Swizzle rgba->bgra if needed.
std::vector<SkPMColor> colors;
@@ -237,16 +203,17 @@ class OopPixelTest : public testing::Test {
SkBitmap RasterExpectedBitmap(
scoped_refptr<DisplayItemList> display_item_list,
const gfx::Size& playback_size) {
- RasterOptions options;
- options.resource_size = playback_size;
- options.full_raster_rect = gfx::Rect(playback_size);
- options.playback_rect = gfx::Rect(playback_size);
+ RasterOptions options(playback_size);
return RasterExpectedBitmap(display_item_list, options);
}
SkBitmap RasterExpectedBitmap(
scoped_refptr<DisplayItemList> display_item_list,
const RasterOptions& options) {
+ TestInProcessContextProvider::ScopedRasterContextLock lock(
+ context_provider_.get());
+ context_provider_->GrContext()->resetContext();
+
// Generate bitmap via the "in process" raster path. This verifies
// that the preamble setup in RasterSource::PlaybackToCanvas matches
// the same setup done in GLES2Implementation::RasterCHROMIUM.
@@ -260,31 +227,24 @@ class OopPixelTest : public testing::Test {
layer_rect);
recording.SetRequiresClear(options.requires_clear);
+ PlaybackImageProvider image_provider(gpu_image_cache_.get(),
+ options.color_space,
+ PlaybackImageProvider::Settings());
+
auto raster_source = recording.CreateRasterSource();
RasterSource::PlaybackSettings settings;
settings.use_lcd_text = options.use_lcd_text;
- // TODO(enne): add a fake image provider here.
+ settings.image_provider = &image_provider;
- uint32_t flags = options.use_distance_field_text
- ? SkSurfaceProps::kUseDistanceFieldFonts_Flag
- : 0;
+ uint32_t flags = 0;
SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
if (options.use_lcd_text) {
surface_props =
SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
}
- gpu::Capabilities capabilities;
- gpu::gles2::GLES2Interface* gl = context_->GetImplementation();
- size_t max_resource_cache_bytes;
- size_t max_glyph_cache_texture_bytes;
- skia_bindings::GrContextForGLES2Interface::DefaultCacheLimitsForTests(
- &max_resource_cache_bytes, &max_glyph_cache_texture_bytes);
- skia_bindings::GrContextForGLES2Interface scoped_grcontext(
- gl, capabilities, max_resource_cache_bytes,
- max_glyph_cache_texture_bytes);
SkImageInfo image_info = SkImageInfo::MakeN32Premul(
options.resource_size.width(), options.resource_size.height());
- auto surface = SkSurface::MakeRenderTarget(scoped_grcontext.get(),
+ auto surface = SkSurface::MakeRenderTarget(context_provider_->GrContext(),
SkBudgeted::kYes, image_info);
SkCanvas* canvas = surface->getCanvas();
if (options.preclear)
@@ -294,13 +254,13 @@ class OopPixelTest : public testing::Test {
gfx::AxisTransform2d raster_transform(options.post_scale,
options.post_translate);
- gfx::ColorSpace target_color_space;
raster_source->PlaybackToCanvas(
canvas, options.color_space, options.content_size,
options.full_raster_rect, options.playback_rect, raster_transform,
settings);
surface->prepareForExternalIO();
- EXPECT_EQ(gl->GetError(), static_cast<unsigned>(GL_NO_ERROR));
+ EXPECT_EQ(context_provider_->ContextGL()->GetError(),
+ static_cast<unsigned>(GL_NO_ERROR));
SkBitmap bitmap;
SkImageInfo info = SkImageInfo::Make(
@@ -309,7 +269,8 @@ class OopPixelTest : public testing::Test {
bitmap.allocPixels(info, options.resource_size.width() * 4);
bool success = surface->readPixels(bitmap, 0, 0);
CHECK(success);
- EXPECT_EQ(gl->GetError(), static_cast<unsigned>(GL_NO_ERROR));
+ EXPECT_EQ(context_provider_->ContextGL()->GetError(),
+ static_cast<unsigned>(GL_NO_ERROR));
return bitmap;
}
@@ -330,17 +291,27 @@ class OopPixelTest : public testing::Test {
}
}
- private:
- viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
- TestImageFactory image_factory_;
- std::unique_ptr<gpu::GLInProcessContext> context_;
- std::unique_ptr<gpu::GLInProcessContext> raster_context_;
- std::unique_ptr<gpu::raster::RasterImplementationGLES> raster_implementation_;
+ protected:
+ enum { kWorkingSetSize = 64 * 1024 * 1024 };
+ scoped_refptr<TestInProcessContextProvider> context_provider_;
+ std::unique_ptr<GpuImageDecodeCache> gpu_image_cache_;
+ std::unique_ptr<GpuImageDecodeCache> oop_image_cache_;
gl::DisableNullDrawGLBindings enable_pixel_output_;
- NoOpImageProvider image_provider_;
+ std::unique_ptr<ImageProvider> image_provider_;
int color_space_id_ = 0;
};
+class OopImagePixelTest : public OopPixelTest,
+ public ::testing::WithParamInterface<bool> {
+ public:
+ bool UseTooLargeImage() { return GetParam(); }
+ gfx::Size GetImageSize() {
+ const int kMaxSize = 20000;
+ DCHECK_GT(kMaxSize, context_provider_->GrContext()->maxTextureSize());
+ return UseTooLargeImage() ? gfx::Size(10, kMaxSize) : gfx::Size(10, 10);
+ }
+};
+
TEST_F(OopPixelTest, DrawColor) {
gfx::Rect rect(10, 10);
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
@@ -349,14 +320,39 @@ TEST_F(OopPixelTest, DrawColor) {
display_item_list->EndPaintOfUnpaired(rect);
display_item_list->Finalize();
- auto actual = Raster(std::move(display_item_list), rect.size());
std::vector<SkPMColor> expected_pixels(rect.width() * rect.height(),
SkPreMultiplyARGB(255, 0, 0, 255));
SkBitmap expected;
expected.installPixels(
SkImageInfo::MakeN32Premul(rect.width(), rect.height()),
expected_pixels.data(), rect.width() * sizeof(SkColor));
+
+ auto actual_oop = Raster(display_item_list, rect.size());
+ ExpectEquals(actual_oop, expected, "oop");
+
+ auto actual_gpu = RasterExpectedBitmap(display_item_list, rect.size());
+ ExpectEquals(actual_gpu, expected, "gpu");
+}
+
+TEST_F(OopPixelTest, DrawColorWithTargetColorSpace) {
+ gfx::Rect rect(10, 10);
+ auto display_item_list = base::MakeRefCounted<DisplayItemList>();
+ display_item_list->StartPaint();
+ display_item_list->push<DrawColorOp>(SK_ColorBLUE, SkBlendMode::kSrc);
+ display_item_list->EndPaintOfUnpaired(rect);
+ display_item_list->Finalize();
+
+ gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50();
+
+ RasterOptions options(rect.size());
+ options.color_space = target_color_space;
+
+ auto actual = Raster(display_item_list, options);
+ auto expected = RasterExpectedBitmap(display_item_list, options);
ExpectEquals(actual, expected);
+
+ // Verify conversion.
+ EXPECT_EQ(SkColorSetARGB(255, 38, 15, 221), expected.getColor(0, 0));
}
TEST_F(OopPixelTest, DrawRect) {
@@ -404,6 +400,156 @@ TEST_F(OopPixelTest, DrawRect) {
ExpectEquals(actual, expected);
}
+TEST_P(OopImagePixelTest, DrawImage) {
+ gfx::Rect rect(10, 10);
+ gfx::Size image_size = GetImageSize();
+
+ SkBitmap bitmap;
+ bitmap.allocPixelsFlags(
+ SkImageInfo::MakeN32Premul(image_size.width(), image_size.height()),
+ SkBitmap::kZeroPixels_AllocFlag);
+
+ SkCanvas canvas(bitmap);
+ canvas.drawColor(SK_ColorMAGENTA);
+ SkPaint green;
+ green.setColor(SK_ColorGREEN);
+ canvas.drawRect(SkRect::MakeXYWH(1, 2, 3, 4), green);
+
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ const PaintImage::Id kSomeId = 32;
+ auto builder =
+ PaintImageBuilder::WithDefault().set_image(image, 0).set_id(kSomeId);
+ auto paint_image = builder.TakePaintImage();
+
+ auto display_item_list = base::MakeRefCounted<DisplayItemList>();
+ display_item_list->StartPaint();
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, nullptr);
+ display_item_list->EndPaintOfUnpaired(rect);
+ display_item_list->Finalize();
+
+ auto actual = Raster(display_item_list, rect.size());
+ auto expected = RasterExpectedBitmap(display_item_list, rect.size());
+ ExpectEquals(actual, expected);
+
+ EXPECT_EQ(actual.getColor(0, 0), SK_ColorMAGENTA);
+}
+
+TEST_P(OopImagePixelTest, DrawImageWithTargetColorSpace) {
+ gfx::Rect rect(10, 10);
+ gfx::Size image_size = GetImageSize();
+
+ SkBitmap bitmap;
+ bitmap.allocPixelsFlags(
+ SkImageInfo::MakeN32Premul(image_size.width(), image_size.height()),
+ SkBitmap::kZeroPixels_AllocFlag);
+
+ SkCanvas canvas(bitmap);
+ canvas.drawColor(SK_ColorMAGENTA);
+ SkPaint green;
+ green.setColor(SK_ColorGREEN);
+ canvas.drawRect(SkRect::MakeXYWH(1, 2, 3, 4), green);
+
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ const PaintImage::Id kSomeId = 32;
+ auto builder =
+ PaintImageBuilder::WithDefault().set_image(image, 0).set_id(kSomeId);
+ auto paint_image = builder.TakePaintImage();
+
+ auto display_item_list = base::MakeRefCounted<DisplayItemList>();
+ display_item_list->StartPaint();
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, nullptr);
+ display_item_list->EndPaintOfUnpaired(rect);
+ display_item_list->Finalize();
+
+ RasterOptions options(rect.size());
+ options.color_space = gfx::ColorSpace::CreateDisplayP3D65();
+
+ auto actual = Raster(display_item_list, options);
+ auto expected = RasterExpectedBitmap(display_item_list, options);
+ ExpectEquals(actual, expected);
+
+ // Verify some conversion occurred here and that actual != bitmap.
+ EXPECT_NE(actual.getColor(0, 0), SK_ColorMAGENTA);
+}
+
+TEST_P(OopImagePixelTest, DrawImageWithSourceColorSpace) {
+ gfx::Rect rect(10, 10);
+ gfx::Size image_size = GetImageSize();
+
+ auto color_space = gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace();
+ SkBitmap bitmap;
+ bitmap.allocPixelsFlags(
+ SkImageInfo::MakeN32Premul(image_size.width(), image_size.height(),
+ color_space),
+ SkBitmap::kZeroPixels_AllocFlag);
+
+ SkCanvas canvas(bitmap);
+ canvas.drawColor(SK_ColorMAGENTA);
+ SkPaint green;
+ green.setColor(SK_ColorGREEN);
+ canvas.drawRect(SkRect::MakeXYWH(1, 2, 3, 4), green);
+
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ const PaintImage::Id kSomeId = 32;
+ auto builder =
+ PaintImageBuilder::WithDefault().set_image(image, 0).set_id(kSomeId);
+ auto paint_image = builder.TakePaintImage();
+ EXPECT_EQ(paint_image.color_space(), color_space.get());
+
+ auto display_item_list = base::MakeRefCounted<DisplayItemList>();
+ display_item_list->StartPaint();
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, nullptr);
+ display_item_list->EndPaintOfUnpaired(rect);
+ display_item_list->Finalize();
+
+ RasterOptions options(rect.size());
+
+ auto actual = Raster(display_item_list, options);
+ auto expected = RasterExpectedBitmap(display_item_list, options);
+ ExpectEquals(actual, expected);
+
+ // Colors get converted when being drawn to the bitmap.
+ EXPECT_NE(bitmap.getColor(0, 0), SK_ColorMAGENTA);
+}
+
+TEST_P(OopImagePixelTest, DrawImageWithSourceAndTargetColorSpace) {
+ gfx::Rect rect(10, 10);
+
+ gfx::Size image_size = GetImageSize();
+ auto color_space = gfx::ColorSpace::CreateXYZD50().ToSkColorSpace();
+ SkBitmap bitmap;
+ bitmap.allocPixelsFlags(
+ SkImageInfo::MakeN32Premul(image_size.width(), image_size.height(),
+ color_space),
+ SkBitmap::kZeroPixels_AllocFlag);
+
+ SkCanvas canvas(bitmap);
+ canvas.drawColor(SK_ColorMAGENTA);
+ SkPaint green;
+ green.setColor(SK_ColorGREEN);
+ canvas.drawRect(SkRect::MakeXYWH(1, 2, 3, 4), green);
+
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ const PaintImage::Id kSomeId = 32;
+ auto builder =
+ PaintImageBuilder::WithDefault().set_image(image, 0).set_id(kSomeId);
+ auto paint_image = builder.TakePaintImage();
+ EXPECT_EQ(paint_image.color_space(), color_space.get());
+
+ auto display_item_list = base::MakeRefCounted<DisplayItemList>();
+ display_item_list->StartPaint();
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, nullptr);
+ display_item_list->EndPaintOfUnpaired(rect);
+ display_item_list->Finalize();
+
+ RasterOptions options(rect.size());
+ options.color_space = gfx::ColorSpace::CreateDisplayP3D65();
+
+ auto actual = Raster(display_item_list, options);
+ auto expected = RasterExpectedBitmap(display_item_list, options);
+ ExpectEquals(actual, expected);
+}
+
TEST_F(OopPixelTest, Preclear) {
gfx::Rect rect(10, 10);
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
@@ -901,5 +1047,7 @@ TEST_F(OopPixelTest, DrawRectColorSpace) {
ExpectEquals(actual, expected);
}
+INSTANTIATE_TEST_CASE_P(P, OopImagePixelTest, ::testing::Values(false, true));
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/paint/paint_filter.cc b/chromium/cc/paint/paint_filter.cc
index 514fb3e9fda..947973cb130 100644
--- a/chromium/cc/paint/paint_filter.cc
+++ b/chromium/cc/paint/paint_filter.cc
@@ -5,6 +5,7 @@
#include "cc/paint/paint_filter.h"
#include "cc/paint/filter_operations.h"
+#include "cc/paint/paint_image_builder.h"
#include "cc/paint/paint_op_writer.h"
#include "cc/paint/paint_record.h"
#include "third_party/skia/include/core/SkColorFilter.h"
@@ -26,6 +27,8 @@
namespace cc {
namespace {
+const bool kHasNoDiscardableImages = false;
+
bool AreFiltersEqual(const PaintFilter* one, const PaintFilter* two) {
if (!one || !two)
return !one && !two;
@@ -36,9 +39,31 @@ bool AreScalarsEqual(SkScalar one, SkScalar two) {
return PaintOp::AreEqualEvenIfNaN(one, two);
}
+bool HasDiscardableImages(const sk_sp<PaintFilter>& filter) {
+ return filter ? filter->has_discardable_images() : false;
+}
+
+bool HasDiscardableImages(const sk_sp<PaintFilter>* const filters, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (filters[i] && filters[i]->has_discardable_images())
+ return true;
+ }
+ return false;
+}
+
+sk_sp<PaintFilter> Snapshot(const sk_sp<PaintFilter>& filter,
+ ImageProvider* image_provider) {
+ if (!filter)
+ return nullptr;
+ return filter->SnapshotWithImages(image_provider);
+}
+
} // namespace
-PaintFilter::PaintFilter(Type type, const CropRect* crop_rect) : type_(type) {
+PaintFilter::PaintFilter(Type type,
+ const CropRect* crop_rect,
+ bool has_discardable_images)
+ : type_(type), has_discardable_images_(has_discardable_images) {
if (crop_rect)
crop_rect_.emplace(*crop_rect);
}
@@ -120,6 +145,13 @@ size_t PaintFilter::BaseSerializedSize() const {
return total_size;
}
+sk_sp<PaintFilter> PaintFilter::SnapshotWithImages(
+ ImageProvider* image_provider) const {
+ if (!has_discardable_images_)
+ return sk_ref_sp<PaintFilter>(this);
+ return SnapshotWithImagesInternal(image_provider);
+}
+
bool PaintFilter::operator==(const PaintFilter& other) const {
if (type_ != other.type_)
return false;
@@ -211,7 +243,7 @@ ColorFilterPaintFilter::ColorFilterPaintFilter(
sk_sp<SkColorFilter> color_filter,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
color_filter_(std::move(color_filter)),
input_(std::move(input)) {
DCHECK(color_filter_);
@@ -229,6 +261,12 @@ size_t ColorFilterPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> ColorFilterPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<ColorFilterPaintFilter>(
+ color_filter_, Snapshot(input_, image_provider), crop_rect());
+}
+
bool ColorFilterPaintFilter::operator==(
const ColorFilterPaintFilter& other) const {
return PaintOp::AreSkFlattenablesEqual(color_filter_.get(),
@@ -241,7 +279,7 @@ BlurPaintFilter::BlurPaintFilter(SkScalar sigma_x,
TileMode tile_mode,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
sigma_x_(sigma_x),
sigma_y_(sigma_y),
tile_mode_(tile_mode),
@@ -260,6 +298,13 @@ size_t BlurPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> BlurPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<BlurPaintFilter>(sigma_x_, sigma_y_, tile_mode_,
+ Snapshot(input_, image_provider),
+ crop_rect());
+}
+
bool BlurPaintFilter::operator==(const BlurPaintFilter& other) const {
return PaintOp::AreEqualEvenIfNaN(sigma_x_, other.sigma_x_) &&
PaintOp::AreEqualEvenIfNaN(sigma_y_, other.sigma_y_) &&
@@ -275,7 +320,7 @@ DropShadowPaintFilter::DropShadowPaintFilter(SkScalar dx,
ShadowMode shadow_mode,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
dx_(dx),
dy_(dy),
sigma_x_(sigma_x),
@@ -298,6 +343,13 @@ size_t DropShadowPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> DropShadowPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<DropShadowPaintFilter>(
+ dx_, dy_, sigma_x_, sigma_y_, color_, shadow_mode_,
+ Snapshot(input_, image_provider), crop_rect());
+}
+
bool DropShadowPaintFilter::operator==(
const DropShadowPaintFilter& other) const {
return PaintOp::AreEqualEvenIfNaN(dx_, other.dx_) &&
@@ -312,7 +364,7 @@ MagnifierPaintFilter::MagnifierPaintFilter(const SkRect& src_rect,
SkScalar inset,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
src_rect_(src_rect),
inset_(inset),
input_(std::move(input)) {
@@ -329,6 +381,12 @@ size_t MagnifierPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> MagnifierPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<MagnifierPaintFilter>(
+ src_rect_, inset_, Snapshot(input_, image_provider), crop_rect());
+}
+
bool MagnifierPaintFilter::operator==(const MagnifierPaintFilter& other) const {
return PaintOp::AreSkRectsEqual(src_rect_, other.src_rect_) &&
PaintOp::AreEqualEvenIfNaN(inset_, other.inset_) &&
@@ -337,7 +395,9 @@ bool MagnifierPaintFilter::operator==(const MagnifierPaintFilter& other) const {
ComposePaintFilter::ComposePaintFilter(sk_sp<PaintFilter> outer,
sk_sp<PaintFilter> inner)
- : PaintFilter(Type::kCompose, nullptr),
+ : PaintFilter(Type::kCompose,
+ nullptr,
+ HasDiscardableImages(outer) || HasDiscardableImages(inner)),
outer_(std::move(outer)),
inner_(std::move(inner)) {
cached_sk_filter_ = SkComposeImageFilter::Make(GetSkFilter(outer_.get()),
@@ -353,6 +413,12 @@ size_t ComposePaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> ComposePaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<ComposePaintFilter>(Snapshot(outer_, image_provider),
+ Snapshot(inner_, image_provider));
+}
+
bool ComposePaintFilter::operator==(const ComposePaintFilter& other) const {
return AreFiltersEqual(outer_.get(), other.outer_.get()) &&
AreFiltersEqual(inner_.get(), other.inner_.get());
@@ -363,7 +429,7 @@ AlphaThresholdPaintFilter::AlphaThresholdPaintFilter(const SkRegion& region,
SkScalar outer_max,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
region_(region),
inner_min_(inner_min),
outer_max_(outer_max),
@@ -383,6 +449,13 @@ size_t AlphaThresholdPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> AlphaThresholdPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<AlphaThresholdPaintFilter>(region_, inner_min_, outer_max_,
+ Snapshot(input_, image_provider),
+ crop_rect());
+}
+
bool AlphaThresholdPaintFilter::operator==(
const AlphaThresholdPaintFilter& other) const {
return region_ == other.region_ &&
@@ -395,7 +468,10 @@ XfermodePaintFilter::XfermodePaintFilter(SkBlendMode blend_mode,
sk_sp<PaintFilter> background,
sk_sp<PaintFilter> foreground,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(
+ kType,
+ crop_rect,
+ HasDiscardableImages(background) || HasDiscardableImages(foreground)),
blend_mode_(blend_mode),
background_(std::move(background)),
foreground_(std::move(foreground)) {
@@ -414,6 +490,13 @@ size_t XfermodePaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> XfermodePaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<XfermodePaintFilter>(
+ blend_mode_, Snapshot(background_, image_provider),
+ Snapshot(foreground_, image_provider), crop_rect());
+}
+
bool XfermodePaintFilter::operator==(const XfermodePaintFilter& other) const {
return blend_mode_ == other.blend_mode_ &&
AreFiltersEqual(background_.get(), other.background_.get()) &&
@@ -428,7 +511,10 @@ ArithmeticPaintFilter::ArithmeticPaintFilter(float k1,
sk_sp<PaintFilter> background,
sk_sp<PaintFilter> foreground,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(
+ kType,
+ crop_rect,
+ HasDiscardableImages(background) || HasDiscardableImages(foreground)),
k1_(k1),
k2_(k2),
k3_(k3),
@@ -452,6 +538,14 @@ size_t ArithmeticPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> ArithmeticPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<ArithmeticPaintFilter>(
+ k1_, k2_, k3_, k4_, enforce_pm_color_,
+ Snapshot(background_, image_provider),
+ Snapshot(foreground_, image_provider), crop_rect());
+}
+
bool ArithmeticPaintFilter::operator==(
const ArithmeticPaintFilter& other) const {
return PaintOp::AreEqualEvenIfNaN(k1_, other.k1_) &&
@@ -473,7 +567,7 @@ MatrixConvolutionPaintFilter::MatrixConvolutionPaintFilter(
bool convolve_alpha,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
kernel_size_(kernel_size),
gain_(gain),
bias_(bias),
@@ -503,6 +597,13 @@ size_t MatrixConvolutionPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> MatrixConvolutionPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<MatrixConvolutionPaintFilter>(
+ kernel_size_, &kernel_[0], gain_, bias_, kernel_offset_, tile_mode_,
+ convolve_alpha_, Snapshot(input_, image_provider), crop_rect());
+}
+
bool MatrixConvolutionPaintFilter::operator==(
const MatrixConvolutionPaintFilter& other) const {
return kernel_size_ == other.kernel_size_ &&
@@ -523,7 +624,10 @@ DisplacementMapEffectPaintFilter::DisplacementMapEffectPaintFilter(
sk_sp<PaintFilter> displacement,
sk_sp<PaintFilter> color,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(
+ kType,
+ crop_rect,
+ HasDiscardableImages(displacement) || HasDiscardableImages(color)),
channel_x_(channel_x),
channel_y_(channel_y),
scale_(scale),
@@ -545,6 +649,13 @@ size_t DisplacementMapEffectPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> DisplacementMapEffectPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<DisplacementMapEffectPaintFilter>(
+ channel_x_, channel_y_, scale_, Snapshot(displacement_, image_provider),
+ Snapshot(color_, image_provider), crop_rect());
+}
+
bool DisplacementMapEffectPaintFilter::operator==(
const DisplacementMapEffectPaintFilter& other) const {
return channel_x_ == other.channel_x_ && channel_y_ == other.channel_y_ &&
@@ -557,7 +668,7 @@ ImagePaintFilter::ImagePaintFilter(PaintImage image,
const SkRect& src_rect,
const SkRect& dst_rect,
SkFilterQuality filter_quality)
- : PaintFilter(kType, nullptr),
+ : PaintFilter(kType, nullptr, image.IsLazyGenerated()),
image_(std::move(image)),
src_rect_(src_rect),
dst_rect_(dst_rect),
@@ -576,6 +687,26 @@ size_t ImagePaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> ImagePaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ DrawImage draw_image(image_, SkIRect::MakeWH(image_.width(), image_.height()),
+ filter_quality_, SkMatrix::I());
+ auto scoped_decoded_image = image_provider->GetDecodedDrawImage(draw_image);
+ if (!scoped_decoded_image)
+ return nullptr;
+
+ auto decoded_sk_image = sk_ref_sp<SkImage>(
+ const_cast<SkImage*>(scoped_decoded_image.decoded_image().image().get()));
+ PaintImage decoded_paint_image =
+ PaintImageBuilder::WithDefault()
+ .set_id(image_.stable_id())
+ .set_image(decoded_sk_image, PaintImage::GetNextContentId())
+ .TakePaintImage();
+
+ return sk_make_sp<ImagePaintFilter>(std::move(decoded_paint_image), src_rect_,
+ dst_rect_, filter_quality_);
+}
+
bool ImagePaintFilter::operator==(const ImagePaintFilter& other) const {
return !!image_ == !!other.image_ &&
PaintOp::AreSkRectsEqual(src_rect_, other.src_rect_) &&
@@ -585,11 +716,16 @@ bool ImagePaintFilter::operator==(const ImagePaintFilter& other) const {
RecordPaintFilter::RecordPaintFilter(sk_sp<PaintRecord> record,
const SkRect& record_bounds)
- : PaintFilter(kType, nullptr),
+ : RecordPaintFilter(std::move(record), record_bounds, nullptr) {}
+
+RecordPaintFilter::RecordPaintFilter(sk_sp<PaintRecord> record,
+ const SkRect& record_bounds,
+ ImageProvider* image_provider)
+ : PaintFilter(kType, nullptr, record->HasDiscardableImages()),
record_(std::move(record)),
record_bounds_(record_bounds) {
- cached_sk_filter_ =
- SkPictureImageFilter::Make(ToSkPicture(record_, record_bounds_));
+ cached_sk_filter_ = SkPictureImageFilter::Make(
+ ToSkPicture(record_, record_bounds_, image_provider));
}
RecordPaintFilter::~RecordPaintFilter() = default;
@@ -601,21 +737,35 @@ size_t RecordPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> RecordPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_sp<RecordPaintFilter>(
+ new RecordPaintFilter(record_, record_bounds_, image_provider));
+}
+
bool RecordPaintFilter::operator==(const RecordPaintFilter& other) const {
return !!record_ == !!other.record_ &&
PaintOp::AreSkRectsEqual(record_bounds_, other.record_bounds_);
}
-MergePaintFilter::MergePaintFilter(sk_sp<PaintFilter>* const filters,
+MergePaintFilter::MergePaintFilter(const sk_sp<PaintFilter>* const filters,
int count,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect) {
+ : MergePaintFilter(filters, count, crop_rect, nullptr) {}
+
+MergePaintFilter::MergePaintFilter(const sk_sp<PaintFilter>* const filters,
+ int count,
+ const CropRect* crop_rect,
+ ImageProvider* image_provider)
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(filters, count)) {
std::vector<sk_sp<SkImageFilter>> sk_filters;
sk_filters.reserve(count);
for (int i = 0; i < count; ++i) {
- inputs_->push_back(filters[i]);
- sk_filters.push_back(GetSkFilter(filters[i].get()));
+ auto filter =
+ image_provider ? Snapshot(filters[i], image_provider) : filters[i];
+ inputs_->push_back(std::move(filter));
+ sk_filters.push_back(GetSkFilter(inputs_->back().get()));
}
cached_sk_filter_ = SkMergeImageFilter::Make(
@@ -633,6 +783,12 @@ size_t MergePaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> MergePaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_sp<MergePaintFilter>(new MergePaintFilter(
+ &inputs_[0], inputs_->size(), crop_rect(), image_provider));
+}
+
bool MergePaintFilter::operator==(const MergePaintFilter& other) const {
if (inputs_->size() != other.inputs_->size())
return false;
@@ -648,7 +804,7 @@ MorphologyPaintFilter::MorphologyPaintFilter(MorphType morph_type,
int radius_y,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
morph_type_(morph_type),
radius_x_(radius_x),
radius_y_(radius_y),
@@ -675,6 +831,13 @@ size_t MorphologyPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> MorphologyPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<MorphologyPaintFilter>(morph_type_, radius_x_, radius_y_,
+ Snapshot(input_, image_provider),
+ crop_rect());
+}
+
bool MorphologyPaintFilter::operator==(
const MorphologyPaintFilter& other) const {
return morph_type_ == other.morph_type_ && radius_x_ == other.radius_x_ &&
@@ -686,7 +849,7 @@ OffsetPaintFilter::OffsetPaintFilter(SkScalar dx,
SkScalar dy,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
dx_(dx),
dy_(dy),
input_(std::move(input)) {
@@ -703,6 +866,12 @@ size_t OffsetPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> OffsetPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<OffsetPaintFilter>(
+ dx_, dy_, Snapshot(input_, image_provider), crop_rect());
+}
+
bool OffsetPaintFilter::operator==(const OffsetPaintFilter& other) const {
return PaintOp::AreEqualEvenIfNaN(dx_, other.dx_) &&
PaintOp::AreEqualEvenIfNaN(dy_, other.dy_) &&
@@ -712,7 +881,7 @@ bool OffsetPaintFilter::operator==(const OffsetPaintFilter& other) const {
TilePaintFilter::TilePaintFilter(const SkRect& src,
const SkRect& dst,
sk_sp<PaintFilter> input)
- : PaintFilter(kType, nullptr),
+ : PaintFilter(kType, nullptr, HasDiscardableImages(input)),
src_(src),
dst_(dst),
input_(std::move(input)) {
@@ -729,6 +898,12 @@ size_t TilePaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> TilePaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<TilePaintFilter>(src_, dst_,
+ Snapshot(input_, image_provider));
+}
+
bool TilePaintFilter::operator==(const TilePaintFilter& other) const {
return PaintOp::AreSkRectsEqual(src_, other.src_) &&
PaintOp::AreSkRectsEqual(dst_, other.dst_) &&
@@ -742,7 +917,7 @@ TurbulencePaintFilter::TurbulencePaintFilter(TurbulenceType turbulence_type,
SkScalar seed,
const SkISize* tile_size,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, kHasNoDiscardableImages),
turbulence_type_(turbulence_type),
base_frequency_x_(base_frequency_x),
base_frequency_y_(base_frequency_y),
@@ -776,6 +951,13 @@ size_t TurbulencePaintFilter::SerializedSize() const {
sizeof(num_octaves_) + sizeof(seed_) + sizeof(tile_size_);
}
+sk_sp<PaintFilter> TurbulencePaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<TurbulencePaintFilter>(turbulence_type_, base_frequency_x_,
+ base_frequency_y_, num_octaves_,
+ seed_, &tile_size_, crop_rect());
+}
+
bool TurbulencePaintFilter::operator==(
const TurbulencePaintFilter& other) const {
return turbulence_type_ == other.turbulence_type_ &&
@@ -790,8 +972,20 @@ bool TurbulencePaintFilter::operator==(
PaintFlagsPaintFilter::PaintFlagsPaintFilter(PaintFlags flags,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect), flags_(std::move(flags)) {
- cached_sk_filter_ = SkPaintImageFilter::Make(flags_.ToSkPaint(), crop_rect);
+ : PaintFlagsPaintFilter(std::move(flags), nullptr, crop_rect) {}
+
+PaintFlagsPaintFilter::PaintFlagsPaintFilter(PaintFlags flags,
+ ImageProvider* image_provider,
+ const CropRect* crop_rect)
+ : PaintFilter(kType, crop_rect, flags.HasDiscardableImages()),
+ flags_(std::move(flags)) {
+ if (image_provider) {
+ raster_flags_.emplace(&flags_, image_provider, SkMatrix::I(), 255u,
+ true /* create_skia_shaders */);
+ }
+ cached_sk_filter_ = SkPaintImageFilter::Make(
+ raster_flags_ ? raster_flags_->flags()->ToSkPaint() : flags_.ToSkPaint(),
+ crop_rect);
}
PaintFlagsPaintFilter::~PaintFlagsPaintFilter() = default;
@@ -802,6 +996,12 @@ size_t PaintFlagsPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> PaintFlagsPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_sp<PaintFilter>(
+ new PaintFlagsPaintFilter(flags_, image_provider, crop_rect()));
+}
+
bool PaintFlagsPaintFilter::operator==(
const PaintFlagsPaintFilter& other) const {
return flags_ == other.flags_;
@@ -810,7 +1010,7 @@ bool PaintFlagsPaintFilter::operator==(
MatrixPaintFilter::MatrixPaintFilter(const SkMatrix& matrix,
SkFilterQuality filter_quality,
sk_sp<PaintFilter> input)
- : PaintFilter(Type::kMatrix, nullptr),
+ : PaintFilter(Type::kMatrix, nullptr, HasDiscardableImages(input)),
matrix_(matrix),
filter_quality_(filter_quality),
input_(std::move(input)) {
@@ -827,6 +1027,12 @@ size_t MatrixPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> MatrixPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<MatrixPaintFilter>(matrix_, filter_quality_,
+ Snapshot(input_, image_provider));
+}
+
bool MatrixPaintFilter::operator==(const MatrixPaintFilter& other) const {
return PaintOp::AreSkMatricesEqual(matrix_, other.matrix_) &&
filter_quality_ == other.filter_quality_ &&
@@ -842,7 +1048,7 @@ LightingDistantPaintFilter::LightingDistantPaintFilter(
SkScalar shininess,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
lighting_type_(lighting_type),
direction_(direction),
light_color_(light_color),
@@ -875,6 +1081,13 @@ size_t LightingDistantPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> LightingDistantPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<LightingDistantPaintFilter>(
+ lighting_type_, direction_, light_color_, surface_scale_, kconstant_,
+ shininess_, Snapshot(input_, image_provider), crop_rect());
+}
+
bool LightingDistantPaintFilter::operator==(
const LightingDistantPaintFilter& other) const {
return lighting_type_ == other.lighting_type_ &&
@@ -894,7 +1107,7 @@ LightingPointPaintFilter::LightingPointPaintFilter(LightingType lighting_type,
SkScalar shininess,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
lighting_type_(lighting_type),
location_(location),
light_color_(light_color),
@@ -927,6 +1140,13 @@ size_t LightingPointPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> LightingPointPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<LightingPointPaintFilter>(
+ lighting_type_, location_, light_color_, surface_scale_, kconstant_,
+ shininess_, Snapshot(input_, image_provider), crop_rect());
+}
+
bool LightingPointPaintFilter::operator==(
const LightingPointPaintFilter& other) const {
return lighting_type_ == other.lighting_type_ &&
@@ -949,7 +1169,7 @@ LightingSpotPaintFilter::LightingSpotPaintFilter(LightingType lighting_type,
SkScalar shininess,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect),
+ : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
lighting_type_(lighting_type),
location_(location),
target_(target),
@@ -987,6 +1207,14 @@ size_t LightingSpotPaintFilter::SerializedSize() const {
return total_size.ValueOrDefault(0u);
}
+sk_sp<PaintFilter> LightingSpotPaintFilter::SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const {
+ return sk_make_sp<LightingSpotPaintFilter>(
+ lighting_type_, location_, target_, specular_exponent_, cutoff_angle_,
+ light_color_, surface_scale_, kconstant_, shininess_,
+ Snapshot(input_, image_provider), crop_rect());
+}
+
bool LightingSpotPaintFilter::operator==(
const LightingSpotPaintFilter& other) const {
return lighting_type_ == other.lighting_type_ &&
diff --git a/chromium/cc/paint/paint_filter.h b/chromium/cc/paint/paint_filter.h
index 162559ccade..cab890edff5 100644
--- a/chromium/cc/paint/paint_filter.h
+++ b/chromium/cc/paint/paint_filter.h
@@ -8,9 +8,11 @@
#include "base/containers/stack_container.h"
#include "base/logging.h"
#include "base/optional.h"
+#include "base/stl_util.h"
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image.h"
+#include "cc/paint/scoped_raster_flags.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkPoint3.h"
@@ -22,10 +24,12 @@
namespace viz {
class GLRenderer;
+class SkiaRenderer;
class SoftwareRenderer;
} // namespace viz
namespace cc {
+class ImageProvider;
class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
public:
@@ -98,11 +102,26 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
return str.c_str();
}
const CropRect* crop_rect() const {
- return crop_rect_ ? &*crop_rect_ : nullptr;
+ return base::OptionalOrNullptr(crop_rect_);
+ }
+
+ bool has_discardable_images() const { return has_discardable_images_; }
+ ImageAnalysisState image_analysis_state() const {
+ return image_analysis_state_;
+ }
+ void set_has_animated_images(bool has_animated_images) {
+ image_analysis_state_ = has_animated_images
+ ? ImageAnalysisState::kAnimatedImages
+ : ImageAnalysisState::kNoAnimatedImages;
}
virtual size_t SerializedSize() const = 0;
+ // Returns a snaphot of the PaintFilter with images replaced using
+ // |image_provider|. Note that this may return the same filter if the filter
+ // has no images.
+ sk_sp<PaintFilter> SnapshotWithImages(ImageProvider* image_provider) const;
+
// Note that this operation is potentially slow. It also only compares things
// that are easy to compare. As an example, it doesn't compare equality of
// images, rather only its existence. This is meant to be used only by tests
@@ -113,7 +132,9 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
bool operator!=(const PaintFilter& other) const { return !(*this == other); }
protected:
- PaintFilter(Type type, const CropRect* crop_rect);
+ PaintFilter(Type type,
+ const CropRect* crop_rect,
+ bool has_discardable_images);
static sk_sp<SkImageFilter> GetSkFilter(const PaintFilter* paint_filter) {
return paint_filter ? paint_filter->cached_sk_filter_ : nullptr;
@@ -123,6 +144,8 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
}
size_t BaseSerializedSize() const;
+ virtual sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const = 0;
// This should be created by each sub-class at construction time, to ensure
// that subsequent access to the filter is thread-safe.
@@ -133,10 +156,14 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
// raster.
friend class PaintFlags;
friend class viz::GLRenderer;
+ friend class viz::SkiaRenderer;
friend class viz::SoftwareRenderer;
const Type type_;
base::Optional<CropRect> crop_rect_;
+ const bool has_discardable_images_;
+
+ ImageAnalysisState image_analysis_state_ = ImageAnalysisState::kNoAnalysis;
DISALLOW_COPY_AND_ASSIGN(PaintFilter);
};
@@ -155,6 +182,10 @@ class CC_PAINT_EXPORT ColorFilterPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const ColorFilterPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
sk_sp<SkColorFilter> color_filter_;
sk_sp<PaintFilter> input_;
@@ -180,6 +211,10 @@ class CC_PAINT_EXPORT BlurPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const BlurPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
SkScalar sigma_x_;
SkScalar sigma_y_;
@@ -212,6 +247,10 @@ class CC_PAINT_EXPORT DropShadowPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const DropShadowPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
SkScalar dx_;
SkScalar dy_;
@@ -238,6 +277,10 @@ class CC_PAINT_EXPORT MagnifierPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const MagnifierPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
SkRect src_rect_;
SkScalar inset_;
@@ -256,6 +299,10 @@ class CC_PAINT_EXPORT ComposePaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const ComposePaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
sk_sp<PaintFilter> outer_;
sk_sp<PaintFilter> inner_;
@@ -279,6 +326,10 @@ class CC_PAINT_EXPORT AlphaThresholdPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const AlphaThresholdPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
SkRegion region_;
SkScalar inner_min_;
@@ -302,6 +353,10 @@ class CC_PAINT_EXPORT XfermodePaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const XfermodePaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
SkBlendMode blend_mode_;
sk_sp<PaintFilter> background_;
@@ -332,6 +387,10 @@ class CC_PAINT_EXPORT ArithmeticPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const ArithmeticPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
float k1_;
float k2_;
@@ -369,6 +428,10 @@ class CC_PAINT_EXPORT MatrixConvolutionPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const MatrixConvolutionPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
SkISize kernel_size_;
base::StackVector<SkScalar, 3> kernel_;
@@ -402,6 +465,10 @@ class CC_PAINT_EXPORT DisplacementMapEffectPaintFilter final
size_t SerializedSize() const override;
bool operator==(const DisplacementMapEffectPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
ChannelSelectorType channel_x_;
ChannelSelectorType channel_y_;
@@ -427,6 +494,10 @@ class CC_PAINT_EXPORT ImagePaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const ImagePaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
PaintImage image_;
SkRect src_rect_;
@@ -446,7 +517,15 @@ class CC_PAINT_EXPORT RecordPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const RecordPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
+ RecordPaintFilter(sk_sp<PaintRecord> record,
+ const SkRect& record_bounds,
+ ImageProvider* image_provider);
+
sk_sp<PaintRecord> record_;
SkRect record_bounds_;
};
@@ -454,7 +533,7 @@ class CC_PAINT_EXPORT RecordPaintFilter final : public PaintFilter {
class CC_PAINT_EXPORT MergePaintFilter final : public PaintFilter {
public:
static constexpr Type kType = Type::kMerge;
- MergePaintFilter(sk_sp<PaintFilter>* const filters,
+ MergePaintFilter(const sk_sp<PaintFilter>* const filters,
int count,
const CropRect* crop_rect = nullptr);
~MergePaintFilter() override;
@@ -468,7 +547,15 @@ class CC_PAINT_EXPORT MergePaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const MergePaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
+ MergePaintFilter(const sk_sp<PaintFilter>* const filters,
+ int count,
+ const CropRect* crop_rect,
+ ImageProvider* image_provider);
base::StackVector<sk_sp<PaintFilter>, 2> inputs_;
};
@@ -491,6 +578,10 @@ class CC_PAINT_EXPORT MorphologyPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const MorphologyPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
MorphType morph_type_;
int radius_x_;
@@ -514,6 +605,10 @@ class CC_PAINT_EXPORT OffsetPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const OffsetPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
SkScalar dx_;
SkScalar dy_;
@@ -535,6 +630,10 @@ class CC_PAINT_EXPORT TilePaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const TilePaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
SkRect src_;
SkRect dst_;
@@ -568,6 +667,10 @@ class CC_PAINT_EXPORT TurbulencePaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const TurbulencePaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
TurbulenceType turbulence_type_;
SkScalar base_frequency_x_;
@@ -589,8 +692,17 @@ class CC_PAINT_EXPORT PaintFlagsPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const PaintFlagsPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
+ PaintFlagsPaintFilter(PaintFlags flags,
+ ImageProvider* image_provider,
+ const CropRect* crop_rect);
+
PaintFlags flags_;
+ base::Optional<ScopedRasterFlags> raster_flags_;
};
class CC_PAINT_EXPORT MatrixPaintFilter final : public PaintFilter {
@@ -608,6 +720,10 @@ class CC_PAINT_EXPORT MatrixPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const MatrixPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
SkMatrix matrix_;
SkFilterQuality filter_quality_;
@@ -641,6 +757,10 @@ class CC_PAINT_EXPORT LightingDistantPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const LightingDistantPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
LightingType lighting_type_;
SkPoint3 direction_;
@@ -678,6 +798,10 @@ class CC_PAINT_EXPORT LightingPointPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const LightingPointPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
LightingType lighting_type_;
SkPoint3 location_;
@@ -721,6 +845,10 @@ class CC_PAINT_EXPORT LightingSpotPaintFilter final : public PaintFilter {
size_t SerializedSize() const override;
bool operator==(const LightingSpotPaintFilter& other) const;
+ protected:
+ sk_sp<PaintFilter> SnapshotWithImagesInternal(
+ ImageProvider* image_provider) const override;
+
private:
LightingType lighting_type_;
SkPoint3 location_;
diff --git a/chromium/cc/paint/paint_filter_unittest.cc b/chromium/cc/paint/paint_filter_unittest.cc
new file mode 100644
index 00000000000..de1ea45132c
--- /dev/null
+++ b/chromium/cc/paint/paint_filter_unittest.cc
@@ -0,0 +1,197 @@
+// 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/paint/paint_filter.h"
+
+#include "cc/paint/paint_op_buffer.h"
+#include "cc/test/skia_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/effects/SkLumaColorFilter.h"
+
+namespace cc {
+namespace {
+
+class MockImageProvider : public ImageProvider {
+ public:
+ MockImageProvider() = default;
+ ~MockImageProvider() override = default;
+
+ ScopedDecodedDrawImage GetDecodedDrawImage(
+ const DrawImage& draw_image) override {
+ image_count_++;
+ return ScopedDecodedDrawImage(DecodedDrawImage(
+ CreateBitmapImage(gfx::Size(10, 10)).GetSkImage(), SkSize::MakeEmpty(),
+ SkSize::Make(1.0f, 1.0f), draw_image.filter_quality(), true));
+ }
+ int image_count_ = 0;
+};
+
+sk_sp<PaintFilter> CreateTestFilter(PaintFilter::Type filter_type,
+ bool has_discardable_images) {
+ PaintImage image;
+ if (has_discardable_images)
+ image = CreateDiscardablePaintImage(gfx::Size(100, 100));
+ else
+ image = CreateBitmapImage(gfx::Size(100, 100));
+
+ auto image_filter = sk_make_sp<ImagePaintFilter>(
+ image, SkRect::MakeWH(100.f, 100.f), SkRect::MakeWH(100.f, 100.f),
+ kNone_SkFilterQuality);
+ auto record = sk_make_sp<PaintOpBuffer>();
+ record->push<DrawImageOp>(image, 0.f, 0.f, nullptr);
+ auto record_filter =
+ sk_make_sp<RecordPaintFilter>(record, SkRect::MakeWH(100.f, 100.f));
+
+ SkImageFilter::CropRect crop_rect(SkRect::MakeWH(100.f, 100.f));
+
+ switch (filter_type) {
+ case PaintFilter::Type::kNullFilter:
+ NOTREACHED();
+ return nullptr;
+ case PaintFilter::Type::kColorFilter:
+ return sk_make_sp<ColorFilterPaintFilter>(SkLumaColorFilter::Make(),
+ image_filter, &crop_rect);
+ case PaintFilter::Type::kBlur:
+ return sk_make_sp<BlurPaintFilter>(0.1f, 0.2f,
+ SkBlurImageFilter::kClamp_TileMode,
+ record_filter, &crop_rect);
+ case PaintFilter::Type::kDropShadow:
+ return sk_make_sp<DropShadowPaintFilter>(
+ 0.1, 0.2f, 0.3f, 0.4f, SK_ColorWHITE,
+ SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode, image_filter,
+ &crop_rect);
+ case PaintFilter::Type::kMagnifier:
+ return sk_make_sp<MagnifierPaintFilter>(SkRect::MakeWH(100.f, 100.f),
+ 0.1f, record_filter, &crop_rect);
+ case PaintFilter::Type::kCompose:
+ return sk_make_sp<ComposePaintFilter>(image_filter, record_filter);
+ case PaintFilter::Type::kAlphaThreshold:
+ return sk_make_sp<AlphaThresholdPaintFilter>(
+ SkRegion(SkIRect::MakeWH(100, 100)), 0.1f, 0.2f, image_filter,
+ &crop_rect);
+ case PaintFilter::Type::kXfermode:
+ return sk_make_sp<XfermodePaintFilter>(SkBlendMode::kSrc, image_filter,
+ record_filter, &crop_rect);
+ case PaintFilter::Type::kArithmetic:
+ return sk_make_sp<ArithmeticPaintFilter>(0.1f, 0.2f, 0.3f, 0.4f, true,
+ image_filter, record_filter,
+ &crop_rect);
+ case PaintFilter::Type::kMatrixConvolution: {
+ SkScalar scalars[9] = {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f};
+ return sk_make_sp<MatrixConvolutionPaintFilter>(
+ SkISize::Make(3, 3), scalars, 0.1f, 0.2f, SkIPoint::Make(2, 2),
+ SkMatrixConvolutionImageFilter::TileMode::kRepeat_TileMode, false,
+ image_filter, &crop_rect);
+ }
+ case PaintFilter::Type::kDisplacementMapEffect:
+ return sk_make_sp<DisplacementMapEffectPaintFilter>(
+ SkDisplacementMapEffect::ChannelSelectorType::kR_ChannelSelectorType,
+ SkDisplacementMapEffect::ChannelSelectorType::kR_ChannelSelectorType,
+ 0.1f, image_filter, record_filter, &crop_rect);
+ case PaintFilter::Type::kImage:
+ return image_filter;
+ case PaintFilter::Type::kPaintRecord:
+ return record_filter;
+ case PaintFilter::Type::kMerge: {
+ sk_sp<PaintFilter> filters[2] = {image_filter, record_filter};
+ return sk_make_sp<MergePaintFilter>(filters, 2, &crop_rect);
+ }
+ case PaintFilter::Type::kMorphology:
+ return sk_make_sp<MorphologyPaintFilter>(
+ MorphologyPaintFilter::MorphType::kDilate, 1, 2, image_filter,
+ &crop_rect);
+ case PaintFilter::Type::kOffset:
+ return sk_make_sp<OffsetPaintFilter>(0.1f, 0.2f, image_filter,
+ &crop_rect);
+ case PaintFilter::Type::kTile:
+ return sk_make_sp<TilePaintFilter>(SkRect::MakeWH(100.f, 100.f),
+ SkRect::MakeWH(200.f, 200.f),
+ record_filter);
+ case PaintFilter::Type::kTurbulence:
+ return sk_make_sp<TurbulencePaintFilter>(
+ TurbulencePaintFilter::TurbulenceType::kTurbulence, 0.1f, 0.2f, 2,
+ 0.3f, nullptr, &crop_rect);
+ case PaintFilter::Type::kPaintFlags: {
+ PaintFlags flags;
+ flags.setShader(PaintShader::MakeImage(image, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode,
+ nullptr));
+ return sk_make_sp<PaintFlagsPaintFilter>(flags, &crop_rect);
+ }
+ case PaintFilter::Type::kMatrix:
+ return sk_make_sp<MatrixPaintFilter>(SkMatrix::I(), kNone_SkFilterQuality,
+ record_filter);
+ case PaintFilter::Type::kLightingDistant:
+ return sk_make_sp<LightingDistantPaintFilter>(
+ PaintFilter::LightingType::kDiffuse, SkPoint3::Make(0.1f, 0.2f, 0.3f),
+ SK_ColorWHITE, 0.1f, 0.2f, 0.3f, image_filter, &crop_rect);
+ case PaintFilter::Type::kLightingPoint:
+ return sk_make_sp<LightingPointPaintFilter>(
+ PaintFilter::LightingType::kDiffuse, SkPoint3::Make(0.1f, 0.2f, 0.3f),
+ SK_ColorWHITE, 0.1f, 0.2f, 0.3f, record_filter, &crop_rect);
+ case PaintFilter::Type::kLightingSpot:
+ return sk_make_sp<LightingSpotPaintFilter>(
+ PaintFilter::LightingType::kDiffuse, SkPoint3::Make(0.1f, 0.2f, 0.3f),
+ SkPoint3::Make(0.4f, 0.5f, 0.6f), 0.1f, 0.2f, SK_ColorWHITE, 0.4f,
+ 0.5f, 0.6f, image_filter, &crop_rect);
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+} // namespace
+
+class PaintFilterTest : public ::testing::TestWithParam<uint8_t> {
+ public:
+ PaintFilter::Type GetParamType() const {
+ return static_cast<PaintFilter::Type>(GetParam());
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(
+ P,
+ PaintFilterTest,
+ ::testing::Range(static_cast<uint8_t>(PaintFilter::Type::kColorFilter),
+ static_cast<uint8_t>(PaintFilter::Type::kMaxFilterType)));
+
+TEST_P(PaintFilterTest, HasDiscardableImagesYes) {
+ // TurbulencePaintFilter can not embed images.
+ if (GetParamType() == PaintFilter::Type::kTurbulence)
+ return;
+
+ EXPECT_TRUE(CreateTestFilter(GetParamType(), true)->has_discardable_images())
+ << PaintFilter::TypeToString(GetParamType());
+}
+
+TEST_P(PaintFilterTest, HasDiscardableImagesNo) {
+ EXPECT_FALSE(
+ CreateTestFilter(GetParamType(), false)->has_discardable_images())
+ << PaintFilter::TypeToString(GetParamType());
+}
+
+TEST_P(PaintFilterTest, SnapshotWithImages) {
+ auto filter = CreateTestFilter(GetParamType(), true);
+ MockImageProvider image_provider;
+ auto snapshot_filter = filter->SnapshotWithImages(&image_provider);
+ if (GetParamType() != PaintFilter::Type::kTurbulence) {
+ // TurbulencePaintFilter can not embed images.
+ EXPECT_GT(image_provider.image_count_, 0)
+ << PaintFilter::TypeToString(GetParamType());
+ }
+ EXPECT_EQ(*filter, *snapshot_filter)
+ << PaintFilter::TypeToString(GetParamType());
+}
+
+TEST(PaintFilterTest, ImageAnalysisState) {
+ auto filter = CreateTestFilter(PaintFilter::Type::kImage, true);
+ EXPECT_EQ(filter->image_analysis_state(), ImageAnalysisState::kNoAnalysis);
+ filter->set_has_animated_images(true);
+ EXPECT_EQ(filter->image_analysis_state(),
+ ImageAnalysisState::kAnimatedImages);
+ filter->set_has_animated_images(false);
+ EXPECT_EQ(filter->image_analysis_state(),
+ ImageAnalysisState::kNoAnimatedImages);
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_flags.cc b/chromium/cc/paint/paint_flags.cc
index 3a75c09ff9d..41b561ff738 100644
--- a/chromium/cc/paint/paint_flags.cc
+++ b/chromium/cc/paint/paint_flags.cc
@@ -36,7 +36,21 @@ PaintFlags::PaintFlags(const PaintFlags& flags) = default;
PaintFlags::PaintFlags(PaintFlags&& other) = default;
-PaintFlags::~PaintFlags() = default;
+PaintFlags::~PaintFlags() {
+ // TODO(enne): non-default dtor to investigate http://crbug.com/790915
+
+ // Sanity check accessing this object doesn't crash.
+ blend_mode_ = static_cast<uint32_t>(SkBlendMode::kLastMode);
+
+ // Free refcounted objects one by one.
+ typeface_.reset();
+ path_effect_.reset();
+ shader_.reset();
+ mask_filter_.reset();
+ color_filter_.reset();
+ draw_looper_.reset();
+ image_filter_.reset();
+}
PaintFlags& PaintFlags::operator=(const PaintFlags& other) = default;
@@ -199,13 +213,8 @@ bool PaintFlags::operator==(const PaintFlags& other) const {
}
bool PaintFlags::HasDiscardableImages() const {
- if (!shader_)
- return false;
- else if (shader_->shader_type() == PaintShader::Type::kImage)
- return shader_->paint_image().IsLazyGenerated();
- else if (shader_->shader_type() == PaintShader::Type::kPaintRecord)
- return shader_->paint_record()->HasDiscardableImages();
- return false;
+ return (shader_ && shader_->has_discardable_images()) ||
+ (image_filter_ && image_filter_->has_discardable_images());
}
size_t PaintFlags::GetSerializedSize() const {
diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h
index 645ee279612..d45fe686ccb 100644
--- a/chromium/cc/paint/paint_image.h
+++ b/chromium/cc/paint/paint_image.h
@@ -53,6 +53,7 @@ class CC_PAINT_EXPORT PaintImage {
uint64_t hash() const { return hash_; }
std::string ToString() const;
size_t frame_index() const { return frame_index_; }
+ ContentId content_id() const { return content_id_; }
private:
ContentId content_id_;
diff --git a/chromium/cc/paint/paint_image_builder.h b/chromium/cc/paint/paint_image_builder.h
index b5e9671b083..b714235275a 100644
--- a/chromium/cc/paint/paint_image_builder.h
+++ b/chromium/cc/paint/paint_image_builder.h
@@ -5,7 +5,6 @@
#ifndef CC_PAINT_PAINT_IMAGE_BUILDER_H_
#define CC_PAINT_PAINT_IMAGE_BUILDER_H_
-#include "base/memory/ptr_util.h"
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_image.h"
#include "cc/paint/paint_image_generator.h"
diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc
index 864a5f39749..446fc6e1ec6 100644
--- a/chromium/cc/paint/paint_op_buffer.cc
+++ b/chromium/cc/paint/paint_op_buffer.cc
@@ -4,7 +4,6 @@
#include "cc/paint/paint_op_buffer.h"
-#include "base/memory/ptr_util.h"
#include "cc/paint/decoded_draw_image.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/image_provider.h"
@@ -269,6 +268,10 @@ std::string PaintOpTypeToString(PaintOpType type) {
return "UNKNOWN";
}
+std::ostream& operator<<(std::ostream& os, PaintOpType type) {
+ return os << PaintOpTypeToString(type);
+}
+
template <typename T>
size_t SimpleSerialize(const PaintOp* op, void* memory, size_t size) {
if (sizeof(T) > size)
@@ -1232,6 +1235,8 @@ void DrawRecordOp::Raster(const DrawRecordOp* op,
SkCanvas* canvas,
const PlaybackParams& params) {
// Don't use drawPicture here, as it adds an implicit clip.
+ // TODO(enne): Temporary CHECK debugging for http://crbug.com/823835
+ CHECK(op->record);
op->record->Playback(canvas, params);
}
@@ -1889,7 +1894,8 @@ bool PaintOp::GetBounds(const PaintOp* op, SkRect* rect) {
// static
bool PaintOp::QuickRejectDraw(const PaintOp* op, const SkCanvas* canvas) {
- DCHECK(op->IsDrawOp());
+ if (!op->IsDrawOp())
+ return false;
SkRect rect;
if (!PaintOp::GetBounds(op, &rect))
@@ -1933,7 +1939,7 @@ void PaintOp::DestroyThis() {
}
bool PaintOpWithFlags::HasDiscardableImagesFromFlags() const {
- return IsDrawOp() && flags.HasDiscardableImages();
+ return flags.HasDiscardableImages();
}
void PaintOpWithFlags::RasterWithFlags(SkCanvas* canvas,
@@ -2048,6 +2054,10 @@ size_t DrawRecordOp::AdditionalBytesUsed() const {
return record->bytes_used();
}
+size_t DrawRecordOp::AdditionalOpCount() const {
+ return record->total_op_count();
+}
+
bool DrawRecordOp::HasDiscardableImages() const {
return record->HasDiscardableImages();
}
@@ -2095,6 +2105,7 @@ void PaintOpBuffer::operator=(PaintOpBuffer&& other) {
op_count_ = other.op_count_;
num_slow_paths_ = other.num_slow_paths_;
subrecord_bytes_used_ = other.subrecord_bytes_used_;
+ subrecord_op_count_ = other.subrecord_op_count_;
has_non_aa_paint_ = other.has_non_aa_paint_;
has_discardable_images_ = other.has_discardable_images_;
@@ -2115,6 +2126,7 @@ void PaintOpBuffer::Reset() {
num_slow_paths_ = 0;
has_non_aa_paint_ = false;
subrecord_bytes_used_ = 0;
+ subrecord_op_count_ = 0;
has_discardable_images_ = false;
}
@@ -2372,6 +2384,8 @@ bool PaintOpBuffer::operator==(const PaintOpBuffer& other) const {
return false;
if (subrecord_bytes_used_ != other.subrecord_bytes_used_)
return false;
+ if (subrecord_op_count_ != other.subrecord_op_count_)
+ return false;
if (has_non_aa_paint_ != other.has_non_aa_paint_)
return false;
if (has_discardable_images_ != other.has_discardable_images_)
diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h
index 122730b8440..2228e487e9a 100644
--- a/chromium/cc/paint/paint_op_buffer.h
+++ b/chromium/cc/paint/paint_op_buffer.h
@@ -90,6 +90,7 @@ enum class PaintOpType : uint8_t {
};
CC_PAINT_EXPORT std::string PaintOpTypeToString(PaintOpType type);
+CC_PAINT_EXPORT std::ostream& operator<<(std::ostream&, PaintOpType);
struct CC_PAINT_EXPORT PlaybackParams {
using CustomDataRasterCallback =
@@ -209,6 +210,9 @@ class CC_PAINT_EXPORT PaintOp {
// and display lists. This doesn't count other objects like paths or blobs.
size_t AdditionalBytesUsed() const { return 0; }
+ // Returns the number of ops in referenced sub records and display lists.
+ size_t AdditionalOpCount() const { return 0; }
+
// Run the destructor for the derived op type. Ops are usually contained in
// memory buffers and so don't have their destructors run automatically.
void DestroyThis();
@@ -600,6 +604,7 @@ class CC_PAINT_EXPORT DrawRecordOp final : public PaintOp {
bool IsValid() const { return true; }
static bool AreEqual(const PaintOp* left, const PaintOp* right);
size_t AdditionalBytesUsed() const;
+ size_t AdditionalOpCount() const;
bool HasDiscardableImages() const;
int CountSlowPaths() const;
bool HasNonAAPaint() const;
@@ -862,6 +867,9 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
size_t bytes_used() const {
return sizeof(*this) + reserved_ + subrecord_bytes_used_;
}
+ // Returns the total number of ops including sub-records.
+ size_t total_op_count() const { return op_count_ + subrecord_op_count_; }
+
size_t next_op_offset() const { return used_; }
int numSlowPaths() const { return num_slow_paths_; }
bool HasNonAAPaint() const { return has_non_aa_paint_; }
@@ -893,6 +901,25 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
AnalyzeAddedOp(op);
}
+ void UpdateSaveLayerBounds(size_t offset, const SkRect& bounds) {
+ CHECK_LT(offset, used_);
+ CHECK_LE(offset + sizeof(PaintOp), used_);
+
+ auto* op = reinterpret_cast<PaintOp*>(data_.get() + offset);
+ switch (op->GetType()) {
+ case SaveLayerOp::kType:
+ CHECK_LE(offset + sizeof(SaveLayerOp), used_);
+ static_cast<SaveLayerOp*>(op)->bounds = bounds;
+ break;
+ case SaveLayerAlphaOp::kType:
+ CHECK_LE(offset + sizeof(SaveLayerAlphaOp), used_);
+ static_cast<SaveLayerAlphaOp*>(op)->bounds = bounds;
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
template <typename T>
void AnalyzeAddedOp(const T* op) {
static_assert(!std::is_same<T, PaintOp>::value,
@@ -907,6 +934,17 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
has_discardable_images_ |= op->HasDiscardableImagesFromFlags();
subrecord_bytes_used_ += op->AdditionalBytesUsed();
+ subrecord_op_count_ += op->AdditionalOpCount();
+ }
+
+ template <typename T>
+ const T* GetOpAtForTesting(size_t index) const {
+ size_t i = 0;
+ for (PaintOpBuffer::Iterator it(this); it && i <= index; ++it, ++i) {
+ if (i == index && (*it)->GetType() == T::kType)
+ return static_cast<const T*>(*it);
+ }
+ return nullptr;
}
class CC_PAINT_EXPORT Iterator {
@@ -1110,6 +1148,8 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
int num_slow_paths_ = 0;
// Record additional bytes used by referenced sub-records and display lists.
size_t subrecord_bytes_used_ = 0;
+ // Record total op count of referenced sub-record and display lists.
+ size_t subrecord_op_count_ = 0;
bool has_non_aa_paint_ : 1;
bool has_discardable_images_ : 1;
diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc
index 88b57dd1d74..7ab3a8c6ad7 100644
--- a/chromium/cc/paint/paint_op_buffer_unittest.cc
+++ b/chromium/cc/paint/paint_op_buffer_unittest.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "cc/paint/paint_op_buffer.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "cc/paint/decoded_draw_image.h"
#include "cc/paint/display_item_list.h"
@@ -19,7 +18,7 @@
#include "cc/test/test_skcanvas.h"
#include "cc/test/transfer_cache_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
+#include "third_party/skia/include/core/SkMaskFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
@@ -1134,9 +1133,8 @@ std::vector<PaintFlags> test_flags = {
SkScalar intervals[] = {1.f, 1.f};
flags.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
- flags.setMaskFilter(
- SkBlurMaskFilter::Make(SkBlurStyle::kOuter_SkBlurStyle, 4.3f,
- test_rects[0], kHigh_SkBlurQuality));
+ flags.setMaskFilter(SkMaskFilter::MakeBlur(
+ SkBlurStyle::kOuter_SkBlurStyle, 4.3f, test_rects[0]));
flags.setColorFilter(SkColorMatrixFilter::MakeLightingFilter(
SK_ColorYELLOW, SK_ColorGREEN));
@@ -1956,7 +1954,7 @@ TEST_P(PaintOpSerializationTest, UsesOverridenFlags) {
PaintOp* written = PaintOp::Deserialize(
output_.get(), bytes_written, deserialized.get(), deserialized_size,
&bytes_read, options_provider.deserialize_options());
- ASSERT_TRUE(written);
+ ASSERT_TRUE(written) << PaintOpTypeToString(GetParamType());
EXPECT_EQ(*op, *written);
written->DestroyThis();
written = nullptr;
@@ -3102,7 +3100,7 @@ TEST(PaintOpBufferTest, RecordShadersSerializeScaledImages) {
record_buffer, SkRect::MakeWH(10.f, 10.f),
SkShader::TileMode::kRepeat_TileMode,
SkShader::TileMode::kRepeat_TileMode, nullptr);
- shader->set_has_animated_images();
+ shader->set_has_animated_images(true);
auto buffer = sk_make_sp<PaintOpBuffer>();
buffer->push<ScaleOp>(0.5f, 0.8f);
PaintFlags flags;
@@ -3125,4 +3123,20 @@ TEST(PaintOpBufferTest, RecordShadersSerializeScaledImages) {
EXPECT_EQ(scale.height(), 0.8f);
}
+TEST(PaintOpBufferTest, TotalOpCount) {
+ auto record_buffer = sk_make_sp<PaintOpBuffer>();
+ auto sub_record_buffer = sk_make_sp<PaintOpBuffer>();
+ auto sub_sub_record_buffer = sk_make_sp<PaintOpBuffer>();
+ PushDrawRectOps(sub_sub_record_buffer.get());
+ PushDrawRectOps(sub_record_buffer.get());
+ PushDrawRectOps(record_buffer.get());
+ sub_record_buffer->push<DrawRecordOp>(sub_sub_record_buffer);
+ record_buffer->push<DrawRecordOp>(sub_record_buffer);
+
+ size_t len = std::min(test_rects.size(), test_flags.size());
+ EXPECT_EQ(len, sub_sub_record_buffer->total_op_count());
+ EXPECT_EQ(2 * len + 1, sub_record_buffer->total_op_count());
+ EXPECT_EQ(3 * len + 2, record_buffer->total_op_count());
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/paint_op_perftest.cc b/chromium/cc/paint/paint_op_perftest.cc
index 93d7ef01134..ee9f92f5eb7 100644
--- a/chromium/cc/paint/paint_op_perftest.cc
+++ b/chromium/cc/paint/paint_op_perftest.cc
@@ -11,7 +11,7 @@
#include "cc/paint/paint_op_buffer_serializer.h"
#include "cc/test/transfer_cache_test_helper.h"
#include "testing/perf/perf_test.h"
-#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
+#include "third_party/skia/include/core/SkMaskFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
@@ -123,9 +123,8 @@ TEST_F(PaintOpPerfTest, ManyFlagsOps) {
PaintFlags flags;
SkScalar intervals[] = {1.f, 1.f};
flags.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
- flags.setMaskFilter(SkBlurMaskFilter::Make(SkBlurStyle::kOuter_SkBlurStyle,
- 4.3f, SkRect::MakeXYWH(1, 1, 1, 1),
- kHigh_SkBlurQuality));
+ flags.setMaskFilter(SkMaskFilter::MakeBlur(
+ SkBlurStyle::kOuter_SkBlurStyle, 4.3f, SkRect::MakeXYWH(1, 1, 1, 1)));
flags.setColorFilter(
SkColorMatrixFilter::MakeLightingFilter(SK_ColorYELLOW, SK_ColorGREEN));
diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc
index b89c8e677dd..2e7dbe089d9 100644
--- a/chromium/cc/paint/paint_op_reader.cc
+++ b/chromium/cc/paint/paint_op_reader.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <algorithm>
+#include "base/stl_util.h"
#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image_builder.h"
@@ -16,6 +17,7 @@
#include "cc/paint/transfer_cache_deserialize_helper.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRRect.h"
+#include "third_party/skia/include/core/SkSerialProcs.h"
#include "third_party/skia/include/core/SkTextBlob.h"
namespace cc {
@@ -32,8 +34,15 @@ struct TypefacesCatalog {
bool had_null = false;
};
-sk_sp<SkTypeface> ResolveTypeface(uint32_t id, void* ctx) {
+sk_sp<SkTypeface> ResolveTypeface(const void* data, size_t length, void* ctx) {
TypefacesCatalog* catalog = static_cast<TypefacesCatalog*>(ctx);
+ if (length != 4) {
+ catalog->had_null = true;
+ return nullptr;
+ }
+
+ uint32_t id;
+ memcpy(&id, data, length);
auto* entry = catalog->transfer_cache
->GetEntryAs<ServicePaintTypefaceTransferCacheEntry>(id);
// TODO(vmpstr): The !entry->typeface() check is here because not all
@@ -359,25 +368,45 @@ void PaintOpReader::Read(sk_sp<SkData>* data) {
remaining_bytes_ -= bytes;
}
-void PaintOpReader::Read(scoped_refptr<PaintTextBlob>* paint_blob) {
- sk_sp<SkData> data;
- Read(&data);
- if (!data || !valid_) {
- SetInvalid();
+void PaintOpReader::Read(sk_sp<SkColorSpace>* color_space) {
+ size_t size = 0;
+ ReadSize(&size);
+ if (remaining_bytes_ < size)
+ valid_ = false;
+ if (!valid_ || size == 0)
return;
- }
- // Skia expects the following to be true, make sure we don't pass it incorrect
- // data.
- if (!data->data() || !SkIsAlign4(data->size())) {
+ // To avoid TOCTOU issues, make a copy of this prior to turning it
+ // into an SkColorSpace. SkColorSpace::Deserialize reads header
+ // fields multiple times, so is not safe to pass memory_ to directly.
+ std::unique_ptr<char[]> data(new char[size]);
+ memcpy(data.get(), const_cast<const char*>(memory_), size);
+
+ *color_space = SkColorSpace::Deserialize(data.get(), size);
+ // If this had non-zero bytes, it should be a valid color space.
+ if (!color_space)
SetInvalid();
+
+ memory_ += size;
+ remaining_bytes_ -= size;
+}
+
+void PaintOpReader::Read(scoped_refptr<PaintTextBlob>* paint_blob) {
+ size_t data_bytes = 0u;
+ ReadSimple(&data_bytes);
+ if (remaining_bytes_ < data_bytes || data_bytes == 0u)
+ SetInvalid();
+ if (!valid_)
return;
- }
TypefacesCatalog catalog;
catalog.transfer_cache = transfer_cache_;
- sk_sp<SkTextBlob> blob = SkTextBlob::Deserialize(data->data(), data->size(),
- &ResolveTypeface, &catalog);
+
+ SkDeserialProcs procs;
+ procs.fTypefaceProc = &ResolveTypeface;
+ procs.fTypefaceCtx = &catalog;
+ sk_sp<SkTextBlob> blob = SkTextBlob::Deserialize(
+ const_cast<const char*>(memory_), data_bytes, procs);
// TODO(vmpstr): If we couldn't serialize |blob|, we should make |paint_blob|
// nullptr. However, this causes GL errors right now, because not all
// typefaces are serialized. Fix this once we serialize everything. For now
@@ -388,6 +417,8 @@ void PaintOpReader::Read(scoped_refptr<PaintTextBlob>* paint_blob) {
blob = nullptr;
*paint_blob = base::MakeRefCounted<PaintTextBlob>(
std::move(blob), std::vector<PaintTypeface>());
+ memory_ += data_bytes;
+ remaining_bytes_ -= data_bytes;
}
void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
@@ -483,7 +514,7 @@ void PaintOpReader::Read(SkMatrix* matrix) {
}
void PaintOpReader::Read(SkColorType* color_type) {
- uint32_t raw_color_type;
+ uint32_t raw_color_type = kUnknown_SkColorType;
ReadSimple(&raw_color_type);
if (raw_color_type > kLastEnum_SkColorType) {
@@ -643,7 +674,7 @@ void PaintOpReader::ReadColorFilterPaintFilter(
return;
filter->reset(new ColorFilterPaintFilter(std::move(color_filter),
std::move(input),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadBlurPaintFilter(
@@ -662,7 +693,7 @@ void PaintOpReader::ReadBlurPaintFilter(
return;
filter->reset(new BlurPaintFilter(sigma_x, sigma_y, tile_mode,
std::move(input),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadDropShadowPaintFilter(
@@ -691,7 +722,7 @@ void PaintOpReader::ReadDropShadowPaintFilter(
return;
filter->reset(new DropShadowPaintFilter(dx, dy, sigma_x, sigma_y, color,
shadow_mode, std::move(input),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadMagnifierPaintFilter(
@@ -707,7 +738,7 @@ void PaintOpReader::ReadMagnifierPaintFilter(
if (!valid_)
return;
filter->reset(new MagnifierPaintFilter(src_rect, inset, std::move(input),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadComposePaintFilter(
@@ -739,7 +770,7 @@ void PaintOpReader::ReadAlphaThresholdPaintFilter(
return;
filter->reset(new AlphaThresholdPaintFilter(
region, inner_min, outer_max, std::move(input),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadXfermodePaintFilter(
@@ -761,7 +792,7 @@ void PaintOpReader::ReadXfermodePaintFilter(
filter->reset(new XfermodePaintFilter(blend_mode, std::move(background),
std::move(foreground),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadArithmeticPaintFilter(
@@ -785,7 +816,7 @@ void PaintOpReader::ReadArithmeticPaintFilter(
return;
filter->reset(new ArithmeticPaintFilter(
k1, k2, k3, k4, enforce_pm_color, std::move(background),
- std::move(foreground), crop_rect ? &*crop_rect : nullptr));
+ std::move(foreground), base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadMatrixConvolutionPaintFilter(
@@ -825,7 +856,7 @@ void PaintOpReader::ReadMatrixConvolutionPaintFilter(
static_cast<MatrixConvolutionPaintFilter::TileMode>(tile_mode_int);
filter->reset(new MatrixConvolutionPaintFilter(
kernel_size, kernel.data(), gain, bias, kernel_offset, tile_mode,
- convolve_alpha, std::move(input), crop_rect ? &*crop_rect : nullptr));
+ convolve_alpha, std::move(input), base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadDisplacementMapEffectPaintFilter(
@@ -860,7 +891,7 @@ void PaintOpReader::ReadDisplacementMapEffectPaintFilter(
channel_y_int);
filter->reset(new DisplacementMapEffectPaintFilter(
channel_x, channel_y, scale, std::move(displacement), std::move(color),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadImagePaintFilter(
@@ -914,7 +945,7 @@ void PaintOpReader::ReadMergePaintFilter(
return;
filter->reset(new MergePaintFilter(inputs.data(),
static_cast<int>(input_count),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadMorphologyPaintFilter(
@@ -938,7 +969,7 @@ void PaintOpReader::ReadMorphologyPaintFilter(
static_cast<MorphologyPaintFilter::MorphType>(morph_type_int);
filter->reset(new MorphologyPaintFilter(morph_type, radius_x, radius_y,
std::move(input),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadOffsetPaintFilter(
@@ -954,7 +985,7 @@ void PaintOpReader::ReadOffsetPaintFilter(
if (!valid_)
return;
filter->reset(new OffsetPaintFilter(dx, dy, std::move(input),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadTilePaintFilter(
@@ -999,7 +1030,7 @@ void PaintOpReader::ReadTurbulencePaintFilter(
static_cast<TurbulencePaintFilter::TurbulenceType>(turbulence_type_int);
filter->reset(new TurbulencePaintFilter(
turbulence_type, base_frequency_x, base_frequency_y, num_octaves, seed,
- &tile_size, crop_rect ? &*crop_rect : nullptr));
+ &tile_size, base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadPaintFlagsPaintFilter(
@@ -1011,7 +1042,7 @@ void PaintOpReader::ReadPaintFlagsPaintFilter(
if (!valid_)
return;
filter->reset(
- new PaintFlagsPaintFilter(flags, crop_rect ? &*crop_rect : nullptr));
+ new PaintFlagsPaintFilter(flags, base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadMatrixPaintFilter(
@@ -1060,7 +1091,7 @@ void PaintOpReader::ReadLightingDistantPaintFilter(
static_cast<PaintFilter::LightingType>(lighting_type_int);
filter->reset(new LightingDistantPaintFilter(
lighting_type, direction, light_color, surface_scale, kconstant,
- shininess, std::move(input), crop_rect ? &*crop_rect : nullptr));
+ shininess, std::move(input), base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadLightingPointPaintFilter(
@@ -1091,7 +1122,7 @@ void PaintOpReader::ReadLightingPointPaintFilter(
static_cast<PaintFilter::LightingType>(lighting_type_int);
filter->reset(new LightingPointPaintFilter(
lighting_type, location, light_color, surface_scale, kconstant, shininess,
- std::move(input), crop_rect ? &*crop_rect : nullptr));
+ std::move(input), base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadLightingSpotPaintFilter(
@@ -1130,7 +1161,7 @@ void PaintOpReader::ReadLightingSpotPaintFilter(
filter->reset(new LightingSpotPaintFilter(
lighting_type, location, target, specular_exponent, cutoff_angle,
light_color, surface_scale, kconstant, shininess, std::move(input),
- crop_rect ? &*crop_rect : nullptr));
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::Read(sk_sp<PaintRecord>* record) {
diff --git a/chromium/cc/paint/paint_op_reader.h b/chromium/cc/paint/paint_op_reader.h
index 03625cd28f5..5fc268af0ec 100644
--- a/chromium/cc/paint/paint_op_reader.h
+++ b/chromium/cc/paint/paint_op_reader.h
@@ -66,6 +66,7 @@ class CC_PAINT_EXPORT PaintOpReader {
void Read(SkMatrix* matrix);
void Read(SkColorType* color_type);
void Read(SkImageInfo* info);
+ void Read(sk_sp<SkColorSpace>* color_space);
void Read(SkClipOp* op) {
uint8_t value = 0u;
diff --git a/chromium/cc/paint/paint_op_writer.cc b/chromium/cc/paint/paint_op_writer.cc
index f70fe61da19..697a9ea4647 100644
--- a/chromium/cc/paint/paint_op_writer.cc
+++ b/chromium/cc/paint/paint_op_writer.cc
@@ -12,16 +12,27 @@
#include "cc/paint/paint_shader.h"
#include "cc/paint/paint_typeface_transfer_cache_entry.h"
#include "cc/paint/transfer_cache_serialize_helper.h"
+#include "third_party/skia/include/core/SkSerialProcs.h"
#include "third_party/skia/include/core/SkTextBlob.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/skia_util.h"
namespace cc {
namespace {
-void TypefaceCataloger(SkTypeface* typeface, void* ctx) {
+const size_t kSkiaAlignment = 4u;
+
+sk_sp<SkData> TypefaceCataloger(SkTypeface* typeface, void* ctx) {
static_cast<TransferCacheSerializeHelper*>(ctx)->AssertLocked(
TransferCacheEntryType::kPaintTypeface, typeface->uniqueID());
+
+ uint32_t id = typeface->uniqueID();
+ return SkData::MakeWithCopy(&id, sizeof(uint32_t));
}
+
+size_t RoundDownToAlignment(size_t bytes, size_t alignment) {
+ return bytes - (bytes & (alignment - 1));
+}
+
} // namespace
// static
@@ -97,16 +108,28 @@ void PaintOpWriter::WriteSimple(const T& val) {
void PaintOpWriter::WriteFlattenable(const SkFlattenable* val) {
DCHECK(SkIsAlign4(reinterpret_cast<uintptr_t>(memory_)))
<< "Flattenable must start writing at 4 byte alignment.";
-
if (!val) {
WriteSize(static_cast<size_t>(0u));
return;
}
- sk_sp<SkData> data = val->serialize();
- WriteSize(data->size());
- if (!data->isEmpty())
- WriteData(data->size(), data->data());
+ size_t size_offset = sizeof(size_t);
+ EnsureBytes(size_offset);
+ if (!valid_)
+ return;
+ char* size_memory = memory_;
+ memory_ += size_offset;
+ remaining_bytes_ -= size_offset;
+
+ size_t bytes_written = val->serialize(
+ memory_, RoundDownToAlignment(remaining_bytes_, kSkiaAlignment));
+ if (bytes_written == 0u) {
+ valid_ = false;
+ return;
+ }
+ reinterpret_cast<size_t*>(size_memory)[0] = bytes_written;
+ memory_ += bytes_written;
+ remaining_bytes_ -= bytes_written;
}
void PaintOpWriter::WriteSize(size_t size) {
@@ -230,9 +253,48 @@ void PaintOpWriter::Write(const sk_sp<SkData>& data) {
}
}
+void PaintOpWriter::Write(const SkColorSpace* color_space) {
+ if (!color_space) {
+ WriteSize(static_cast<size_t>(0));
+ return;
+ }
+ size_t size = color_space->writeToMemory(nullptr);
+ WriteSize(size);
+
+ EnsureBytes(size);
+ if (!valid_)
+ return;
+
+ size_t written = color_space->writeToMemory(memory_);
+ CHECK_EQ(written, size);
+
+ memory_ += written;
+ remaining_bytes_ -= written;
+}
+
void PaintOpWriter::Write(const sk_sp<SkTextBlob>& blob) {
- auto data = blob->serialize(&TypefaceCataloger, transfer_cache_);
- Write(data);
+ DCHECK(blob);
+
+ size_t size_offset = sizeof(size_t);
+ EnsureBytes(size_offset);
+ if (!valid_)
+ return;
+
+ char* size_memory = memory_;
+ memory_ += size_offset;
+ remaining_bytes_ -= size_offset;
+ SkSerialProcs procs;
+ procs.fTypefaceProc = &TypefaceCataloger;
+ procs.fTypefaceCtx = transfer_cache_;
+ size_t bytes_written = blob->serialize(
+ procs, memory_, RoundDownToAlignment(remaining_bytes_, kSkiaAlignment));
+ if (bytes_written == 0u) {
+ valid_ = false;
+ return;
+ }
+ reinterpret_cast<size_t*>(size_memory)[0] = bytes_written;
+ memory_ += bytes_written;
+ remaining_bytes_ -= bytes_written;
}
void PaintOpWriter::Write(const scoped_refptr<PaintTextBlob>& blob) {
diff --git a/chromium/cc/paint/paint_op_writer.h b/chromium/cc/paint/paint_op_writer.h
index 63fd7536f66..685ff92c857 100644
--- a/chromium/cc/paint/paint_op_writer.h
+++ b/chromium/cc/paint/paint_op_writer.h
@@ -60,6 +60,7 @@ class CC_PAINT_EXPORT PaintOpWriter {
void Write(const PaintFlags& flags);
void Write(const DrawImage& image);
void Write(const sk_sp<SkData>& data);
+ void Write(const SkColorSpace* data);
void Write(const PaintShader* shader);
void Write(const PaintFilter* filter);
void Write(const scoped_refptr<PaintTextBlob>& blob);
diff --git a/chromium/cc/paint/paint_record.cc b/chromium/cc/paint/paint_record.cc
index 9593bbb25bd..6609e82ee05 100644
--- a/chromium/cc/paint/paint_record.cc
+++ b/chromium/cc/paint/paint_record.cc
@@ -9,18 +9,23 @@
namespace cc {
-sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record, const SkRect& bounds) {
+sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record,
+ const SkRect& bounds,
+ ImageProvider* image_provider) {
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(bounds);
- record->Playback(canvas);
+ PlaybackParams params(image_provider);
+ record->Playback(canvas, params);
return recorder.finishRecordingAsPicture();
}
sk_sp<const SkPicture> ToSkPicture(sk_sp<const PaintRecord> record,
- const SkRect& bounds) {
+ const SkRect& bounds,
+ ImageProvider* image_provider) {
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(bounds);
- record->Playback(canvas);
+ PlaybackParams params(image_provider);
+ record->Playback(canvas, params);
return recorder.finishRecordingAsPicture();
}
diff --git a/chromium/cc/paint/paint_record.h b/chromium/cc/paint/paint_record.h
index 1509bac0529..6e0c1d77c85 100644
--- a/chromium/cc/paint/paint_record.h
+++ b/chromium/cc/paint/paint_record.h
@@ -10,6 +10,7 @@
#include "third_party/skia/include/core/SkPicture.h"
namespace cc {
+class ImageProvider;
// TODO(enne): Don't want to rename the world for this. Using these as the
// same types for now prevents an extra allocation. Probably PaintRecord
@@ -17,12 +18,15 @@ namespace cc {
using PaintRecord = PaintOpBuffer;
// TODO(enne): Remove these if possible, they are really expensive.
-CC_PAINT_EXPORT sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record,
- const SkRect& bounds);
+CC_PAINT_EXPORT sk_sp<SkPicture> ToSkPicture(
+ sk_sp<PaintRecord> record,
+ const SkRect& bounds,
+ ImageProvider* image_provider = nullptr);
CC_PAINT_EXPORT sk_sp<const SkPicture> ToSkPicture(
sk_sp<const PaintRecord> record,
- const SkRect& bounds);
+ const SkRect& bounds,
+ ImageProvider* image_provider = nullptr);
} // namespace cc
diff --git a/chromium/cc/paint/paint_recorder.h b/chromium/cc/paint/paint_recorder.h
index 1b0bf24d01d..c8f1c8a0ab8 100644
--- a/chromium/cc/paint/paint_recorder.h
+++ b/chromium/cc/paint/paint_recorder.h
@@ -7,7 +7,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/record_paint_canvas.h"
diff --git a/chromium/cc/paint/paint_shader.cc b/chromium/cc/paint/paint_shader.cc
index 104ada8c4e6..6baee9fe6d3 100644
--- a/chromium/cc/paint/paint_shader.cc
+++ b/chromium/cc/paint/paint_shader.cc
@@ -4,7 +4,6 @@
#include "cc/paint/paint_shader.h"
-#include "base/memory/ptr_util.h"
#include "cc/paint/paint_op_writer.h"
#include "cc/paint/paint_record.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -186,6 +185,11 @@ size_t PaintShader::GetSerializedSize(const PaintShader* shader) {
PaintShader::PaintShader(Type type) : shader_type_(type) {}
PaintShader::~PaintShader() = default;
+bool PaintShader::has_discardable_images() const {
+ return (image_ && image_.IsLazyGenerated()) ||
+ (record_ && record_->HasDiscardableImages());
+}
+
bool PaintShader::GetRasterizationTileRect(const SkMatrix& ctm,
SkRect* tile_rect) const {
DCHECK_EQ(shader_type_, Type::kPaintRecord);
@@ -288,7 +292,7 @@ void PaintShader::CreateSkShader(ImageProvider* image_provider) {
points, colors_.data(),
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, flags_,
- local_matrix_ ? &*local_matrix_ : nullptr);
+ base::OptionalOrNullptr(local_matrix_));
break;
}
case Type::kRadialGradient:
@@ -296,26 +300,26 @@ void PaintShader::CreateSkShader(ImageProvider* image_provider) {
center_, start_radius_, colors_.data(),
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, flags_,
- local_matrix_ ? &*local_matrix_ : nullptr);
+ base::OptionalOrNullptr(local_matrix_));
break;
case Type::kTwoPointConicalGradient:
cached_shader_ = SkGradientShader::MakeTwoPointConical(
start_point_, start_radius_, end_point_, end_radius_, colors_.data(),
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, flags_,
- local_matrix_ ? &*local_matrix_ : nullptr);
+ base::OptionalOrNullptr(local_matrix_));
break;
case Type::kSweepGradient:
cached_shader_ = SkGradientShader::MakeSweep(
center_.x(), center_.y(), colors_.data(),
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, start_degrees_, end_degrees_,
- flags_, local_matrix_ ? &*local_matrix_ : nullptr);
+ flags_, base::OptionalOrNullptr(local_matrix_));
break;
case Type::kImage:
if (image_) {
cached_shader_ = image_.GetSkImage()->makeShader(
- tx_, ty_, local_matrix_ ? &*local_matrix_ : nullptr);
+ tx_, ty_, base::OptionalOrNullptr(local_matrix_));
}
break;
case Type::kPaintRecord: {
@@ -328,7 +332,7 @@ void PaintShader::CreateSkShader(ImageProvider* image_provider) {
case ScalingBehavior::kRasterAtScale:
cached_shader_ = SkShader::MakePictureShader(
std::move(picture), tx_, ty_,
- local_matrix_ ? &*local_matrix_ : nullptr, nullptr);
+ base::OptionalOrNullptr(local_matrix_), nullptr);
break;
// For fixed scale, we create an image shader with an image backed by
// the picture.
@@ -338,7 +342,7 @@ void PaintShader::CreateSkShader(ImageProvider* image_provider) {
nullptr, nullptr, SkImage::BitDepth::kU8,
SkColorSpace::MakeSRGB());
cached_shader_ = image->makeShader(
- tx_, ty_, local_matrix_ ? &*local_matrix_ : nullptr);
+ tx_, ty_, base::OptionalOrNullptr(local_matrix_));
break;
}
}
diff --git a/chromium/cc/paint/paint_shader.h b/chromium/cc/paint/paint_shader.h
index f5e7f4f49b4..6c197b7919d 100644
--- a/chromium/cc/paint/paint_shader.h
+++ b/chromium/cc/paint/paint_shader.h
@@ -9,6 +9,8 @@
#include <vector>
#include "base/optional.h"
+#include "base/stl_util.h"
+#include "cc/paint/image_analysis_state.h"
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_image.h"
#include "third_party/skia/include/core/SkImage.h"
@@ -105,8 +107,16 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
~PaintShader() override;
- void set_has_animated_images() { has_animated_images_ = true; }
- bool has_animated_images() const { return has_animated_images_; }
+ void set_has_animated_images(bool has_animated_images) {
+ image_analysis_state_ = has_animated_images
+ ? ImageAnalysisState::kAnimatedImages
+ : ImageAnalysisState::kNoAnimatedImages;
+ }
+ ImageAnalysisState image_analysis_state() const {
+ return image_analysis_state_;
+ }
+
+ bool has_discardable_images() const;
SkMatrix GetLocalMatrix() const {
return local_matrix_ ? *local_matrix_ : SkMatrix::I();
@@ -118,7 +128,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
}
const gfx::SizeF* tile_scale() const {
- return tile_scale_ ? &*tile_scale_ : nullptr;
+ return base::OptionalOrNullptr(tile_scale_);
}
const sk_sp<PaintRecord>& paint_record() const { return record_; }
bool GetRasterizationTileRect(const SkMatrix& ctm, SkRect* tile_rect) const;
@@ -199,7 +209,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
// accesses to it are thread-safe.
sk_sp<SkShader> cached_shader_;
- bool has_animated_images_ = false;
+ ImageAnalysisState image_analysis_state_ = ImageAnalysisState::kNoAnalysis;
DISALLOW_COPY_AND_ASSIGN(PaintShader);
};
diff --git a/chromium/cc/paint/paint_shader_unittest.cc b/chromium/cc/paint/paint_shader_unittest.cc
index 55ce7c5211c..ac6f9e0f435 100644
--- a/chromium/cc/paint/paint_shader_unittest.cc
+++ b/chromium/cc/paint/paint_shader_unittest.cc
@@ -84,7 +84,7 @@ TEST(PaintShaderTest, DecodePaintRecord) {
auto record_shader = PaintShader::MakePaintRecord(
record, SkRect::MakeWH(100, 100), SkShader::TileMode::kClamp_TileMode,
SkShader::TileMode::kClamp_TileMode, &local_matrix);
- record_shader->set_has_animated_images();
+ record_shader->set_has_animated_images(true);
PaintOpBuffer buffer;
PaintFlags flags;
diff --git a/chromium/cc/paint/paint_text_blob.h b/chromium/cc/paint/paint_text_blob.h
index 2bdac367b32..ff6b4f54e99 100644
--- a/chromium/cc/paint/paint_text_blob.h
+++ b/chromium/cc/paint/paint_text_blob.h
@@ -22,7 +22,7 @@ class CC_PAINT_EXPORT PaintTextBlob
PaintTextBlob(sk_sp<SkTextBlob> blob, std::vector<PaintTypeface> typefaces);
const sk_sp<SkTextBlob>& ToSkTextBlob() const { return sk_blob_; }
- const std::vector<PaintTypeface> typefaces() const { return typefaces_; }
+ const std::vector<PaintTypeface>& typefaces() const { return typefaces_; }
operator bool() const { return !!sk_blob_; }
diff --git a/chromium/cc/paint/paint_typeface_transfer_cache_entry.cc b/chromium/cc/paint/paint_typeface_transfer_cache_entry.cc
index 78235671290..34def03d2cb 100644
--- a/chromium/cc/paint/paint_typeface_transfer_cache_entry.cc
+++ b/chromium/cc/paint/paint_typeface_transfer_cache_entry.cc
@@ -118,7 +118,7 @@ size_t ServicePaintTypefaceTransferCacheEntry::CachedSize() const {
bool ServicePaintTypefaceTransferCacheEntry::Deserialize(
GrContext* context,
- base::span<uint8_t> data) {
+ base::span<const uint8_t> data) {
data_ = data;
size_t initial_size = data_.size();
@@ -198,7 +198,7 @@ bool ServicePaintTypefaceTransferCacheEntry::Deserialize(
// Set the size to however much data we read.
size_ = initial_size - data_.size();
- data_ = base::span<uint8_t>(nullptr);
+ data_ = base::span<uint8_t>();
return valid_;
}
@@ -208,7 +208,7 @@ void ServicePaintTypefaceTransferCacheEntry::ReadSimple(T* val) {
valid_ = false;
if (!valid_)
return;
- *val = *reinterpret_cast<T*>(data_.data());
+ *val = *reinterpret_cast<const T*>(data_.data());
data_ = data_.subspan(sizeof(T));
}
diff --git a/chromium/cc/paint/paint_typeface_transfer_cache_entry.h b/chromium/cc/paint/paint_typeface_transfer_cache_entry.h
index 938c66b844a..f1c1e75129e 100644
--- a/chromium/cc/paint/paint_typeface_transfer_cache_entry.h
+++ b/chromium/cc/paint/paint_typeface_transfer_cache_entry.h
@@ -37,7 +37,7 @@ class CC_PAINT_EXPORT ServicePaintTypefaceTransferCacheEntry
ServicePaintTypefaceTransferCacheEntry();
~ServicePaintTypefaceTransferCacheEntry() final;
size_t CachedSize() const final;
- bool Deserialize(GrContext* context, base::span<uint8_t> data) final;
+ bool Deserialize(GrContext* context, base::span<const uint8_t> data) final;
const PaintTypeface& typeface() const { return typeface_; }
@@ -50,7 +50,9 @@ class CC_PAINT_EXPORT ServicePaintTypefaceTransferCacheEntry
PaintTypeface typeface_;
size_t size_ = 0;
bool valid_ = true;
- base::span<uint8_t> data_;
+ // TODO(enne): this transient value shouldn't be a member and should just be
+ // passed around internally to functions that need it.
+ base::span<const uint8_t> data_;
};
} // namespace cc
diff --git a/chromium/cc/paint/raw_memory_transfer_cache_entry.cc b/chromium/cc/paint/raw_memory_transfer_cache_entry.cc
index 07e51c01c92..2c41fabd9d9 100644
--- a/chromium/cc/paint/raw_memory_transfer_cache_entry.cc
+++ b/chromium/cc/paint/raw_memory_transfer_cache_entry.cc
@@ -43,8 +43,9 @@ size_t ServiceRawMemoryTransferCacheEntry::CachedSize() const {
return data_.size();
}
-bool ServiceRawMemoryTransferCacheEntry::Deserialize(GrContext* context,
- base::span<uint8_t> data) {
+bool ServiceRawMemoryTransferCacheEntry::Deserialize(
+ GrContext* context,
+ base::span<const uint8_t> data) {
data_ = std::vector<uint8_t>(data.begin(), data.end());
return true;
}
diff --git a/chromium/cc/paint/raw_memory_transfer_cache_entry.h b/chromium/cc/paint/raw_memory_transfer_cache_entry.h
index d5efd624ba4..c6ce52af731 100644
--- a/chromium/cc/paint/raw_memory_transfer_cache_entry.h
+++ b/chromium/cc/paint/raw_memory_transfer_cache_entry.h
@@ -37,7 +37,7 @@ class CC_PAINT_EXPORT ServiceRawMemoryTransferCacheEntry
ServiceRawMemoryTransferCacheEntry();
~ServiceRawMemoryTransferCacheEntry() final;
size_t CachedSize() const final;
- bool Deserialize(GrContext* context, base::span<uint8_t> data) final;
+ bool Deserialize(GrContext* context, base::span<const uint8_t> data) final;
const std::vector<uint8_t>& data() { return data_; }
private:
diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc
index a39f278836f..c601f19296d 100644
--- a/chromium/cc/paint/record_paint_canvas.cc
+++ b/chromium/cc/paint/record_paint_canvas.cc
@@ -4,7 +4,6 @@
#include "cc/paint/record_paint_canvas.h"
-#include "base/memory/ptr_util.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_image_builder.h"
#include "cc/paint/paint_record.h"
diff --git a/chromium/cc/paint/scoped_raster_flags.cc b/chromium/cc/paint/scoped_raster_flags.cc
index 6e45512c0e1..b54f137e1dc 100644
--- a/chromium/cc/paint/scoped_raster_flags.cc
+++ b/chromium/cc/paint/scoped_raster_flags.cc
@@ -5,6 +5,7 @@
#include "cc/paint/scoped_raster_flags.h"
#include "cc/paint/image_provider.h"
+#include "cc/paint/paint_filter.h"
#include "cc/paint/paint_image_builder.h"
namespace cc {
@@ -15,22 +16,19 @@ ScopedRasterFlags::ScopedRasterFlags(const PaintFlags* flags,
bool create_skia_shader)
: original_flags_(flags) {
if (flags->HasDiscardableImages() && image_provider) {
- DCHECK(flags->HasShader());
-
// TODO(khushalsagar): The decoding of images in PaintFlags here is a bit of
// a mess. We decode image shaders at the correct scale but ignore that
// during serialization and just use the original image.
decode_stashing_image_provider_.emplace(image_provider);
- if (flags->getShader()->shader_type() == PaintShader::Type::kImage) {
- DecodeImageShader(ctm);
- } else if (flags->getShader()->shader_type() ==
- PaintShader::Type::kPaintRecord) {
- DecodeRecordShader(ctm, create_skia_shader);
- } else {
- NOTREACHED();
- }
// We skip the op if any images fail to decode.
+ DecodeImageShader(ctm);
+ if (decode_failed_)
+ return;
+ DecodeRecordShader(ctm, create_skia_shader);
+ if (decode_failed_)
+ return;
+ DecodeFilter();
if (decode_failed_)
return;
}
@@ -46,6 +44,10 @@ ScopedRasterFlags::ScopedRasterFlags(const PaintFlags* flags,
ScopedRasterFlags::~ScopedRasterFlags() = default;
void ScopedRasterFlags::DecodeImageShader(const SkMatrix& ctm) {
+ if (!flags()->HasShader() ||
+ flags()->getShader()->shader_type() != PaintShader::Type::kImage)
+ return;
+
const PaintImage& paint_image = flags()->getShader()->paint_image();
SkMatrix matrix = flags()->getShader()->GetLocalMatrix();
@@ -100,9 +102,14 @@ void ScopedRasterFlags::DecodeImageShader(const SkMatrix& ctm) {
void ScopedRasterFlags::DecodeRecordShader(const SkMatrix& ctm,
bool create_skia_shader) {
+ if (!flags()->HasShader() ||
+ flags()->getShader()->shader_type() != PaintShader::Type::kPaintRecord)
+ return;
+
// TODO(khushalsagar): For OOP, we have to decode everything during
// serialization. This will force us to use original sized decodes.
- if (!flags()->getShader()->has_animated_images())
+ if (flags()->getShader()->image_analysis_state() !=
+ ImageAnalysisState::kAnimatedImages)
return;
auto decoded_shader = flags()->getShader()->CreateDecodedPaintRecord(
@@ -117,6 +124,18 @@ void ScopedRasterFlags::DecodeRecordShader(const SkMatrix& ctm,
MutableFlags()->setShader(std::move(decoded_shader));
}
+void ScopedRasterFlags::DecodeFilter() {
+ if (!flags()->getImageFilter() ||
+ !flags()->getImageFilter()->has_discardable_images() ||
+ flags()->getImageFilter()->image_analysis_state() !=
+ ImageAnalysisState::kAnimatedImages) {
+ return;
+ }
+
+ MutableFlags()->setImageFilter(flags()->getImageFilter()->SnapshotWithImages(
+ &*decode_stashing_image_provider_));
+}
+
void ScopedRasterFlags::AdjustStrokeIfNeeded(const SkMatrix& ctm) {
// With anti-aliasing turned off, strokes with a device space width in (0, 1)
// may not raster at all. To avoid this, we have two options:
diff --git a/chromium/cc/paint/scoped_raster_flags.h b/chromium/cc/paint/scoped_raster_flags.h
index 5b2f859c321..5407b5e2655 100644
--- a/chromium/cc/paint/scoped_raster_flags.h
+++ b/chromium/cc/paint/scoped_raster_flags.h
@@ -37,6 +37,8 @@ class CC_PAINT_EXPORT ScopedRasterFlags {
private:
void DecodeImageShader(const SkMatrix& ctm);
void DecodeRecordShader(const SkMatrix& ctm, bool create_skia_shader);
+ void DecodeFilter();
+
void AdjustStrokeIfNeeded(const SkMatrix& ctm);
PaintFlags* MutableFlags() {
diff --git a/chromium/cc/paint/scoped_raster_flags_unittest.cc b/chromium/cc/paint/scoped_raster_flags_unittest.cc
index c912d07e63f..b0ac2654d1d 100644
--- a/chromium/cc/paint/scoped_raster_flags_unittest.cc
+++ b/chromium/cc/paint/scoped_raster_flags_unittest.cc
@@ -54,7 +54,7 @@ TEST(ScopedRasterFlagsTest, KeepsDecodesAlive) {
auto record_shader = PaintShader::MakePaintRecord(
record, SkRect::MakeWH(100, 100), SkShader::TileMode::kClamp_TileMode,
SkShader::TileMode::kClamp_TileMode, &SkMatrix::I());
- record_shader->set_has_animated_images();
+ record_shader->set_has_animated_images(true);
MockImageProvider provider;
PaintFlags flags;
diff --git a/chromium/cc/paint/skia_paint_canvas.cc b/chromium/cc/paint/skia_paint_canvas.cc
index f9caa002ebb..83128d5c3a6 100644
--- a/chromium/cc/paint/skia_paint_canvas.cc
+++ b/chromium/cc/paint/skia_paint_canvas.cc
@@ -4,7 +4,6 @@
#include "cc/paint/skia_paint_canvas.h"
-#include "base/memory/ptr_util.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_recorder.h"
#include "cc/paint/scoped_raster_flags.h"
diff --git a/chromium/cc/paint/transfer_cache_entry.cc b/chromium/cc/paint/transfer_cache_entry.cc
index 785bb3078a1..46252c1850d 100644
--- a/chromium/cc/paint/transfer_cache_entry.cc
+++ b/chromium/cc/paint/transfer_cache_entry.cc
@@ -27,7 +27,6 @@ std::unique_ptr<ServiceTransferCacheEntry> ServiceTransferCacheEntry::Create(
return std::make_unique<ServiceColorSpaceTransferCacheEntry>();
}
- NOTREACHED();
return nullptr;
}
diff --git a/chromium/cc/paint/transfer_cache_entry.h b/chromium/cc/paint/transfer_cache_entry.h
index 5e0e9179969..9ecde14aedc 100644
--- a/chromium/cc/paint/transfer_cache_entry.h
+++ b/chromium/cc/paint/transfer_cache_entry.h
@@ -82,7 +82,8 @@ class CC_PAINT_EXPORT ServiceTransferCacheEntry {
// Deserialize the cache entry from the given span of memory with the given
// context.
- virtual bool Deserialize(GrContext* context, base::span<uint8_t> data) = 0;
+ virtual bool Deserialize(GrContext* context,
+ base::span<const uint8_t> data) = 0;
};
// Helpers to simplify subclassing.
diff --git a/chromium/cc/paint/transfer_cache_fuzzer.cc b/chromium/cc/paint/transfer_cache_fuzzer.cc
new file mode 100644
index 00000000000..54e2bee949e
--- /dev/null
+++ b/chromium/cc/paint/transfer_cache_fuzzer.cc
@@ -0,0 +1,41 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include "cc/paint/paint_op_buffer.h"
+#include "cc/paint/raw_memory_transfer_cache_entry.h"
+#include "cc/test/transfer_cache_test_helper.h"
+#include "components/viz/test/test_context_provider.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size < 4)
+ return 0;
+
+ scoped_refptr<viz::TestContextProvider> context_provider =
+ viz::TestContextProvider::Create();
+ context_provider->BindToCurrentThread();
+
+ cc::TransferCacheEntryType entry_type =
+ static_cast<cc::TransferCacheEntryType>(data[0]);
+ std::unique_ptr<cc::ServiceTransferCacheEntry> entry =
+ cc::ServiceTransferCacheEntry::Create(entry_type);
+ if (!entry)
+ return 0;
+
+ // Align data.
+ base::span<const uint8_t> span(&data[4], size - 4);
+ if (!entry->Deserialize(context_provider->GrContext(), span))
+ return 0;
+
+ // TODO(enne): consider running Serialize() here to fuzz that codepath
+ // for bugs. However, that requires setting up a real context with
+ // a raster interface that supports gl operations and that has a
+ // TransferCacheTestHelper in it so the innards of client and service
+ // are accessible.
+ return 0;
+}
diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.cc b/chromium/cc/raster/bitmap_raster_buffer_provider.cc
index def2324480b..ae5744092af 100644
--- a/chromium/cc/raster/bitmap_raster_buffer_provider.cc
+++ b/chromium/cc/raster/bitmap_raster_buffer_provider.cc
@@ -10,23 +10,35 @@
#include <algorithm>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/raster/raster_source.h"
-#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/resources/resource.h"
+#include "cc/trees/layer_tree_frame_sink.h"
+#include "components/viz/common/resources/bitmap_allocation.h"
#include "components/viz/common/resources/platform_color.h"
-#include "components/viz/common/resources/shared_bitmap_manager.h"
namespace cc {
namespace {
+class BitmapSoftwareBacking : public ResourcePool::SoftwareBacking {
+ public:
+ ~BitmapSoftwareBacking() override {
+ frame_sink->DidDeleteSharedBitmap(shared_bitmap_id);
+ }
+
+ base::UnguessableToken SharedMemoryGuid() override {
+ return shared_memory->mapped_id();
+ }
+
+ LayerTreeFrameSink* frame_sink;
+ std::unique_ptr<base::SharedMemory> shared_memory;
+};
+
class BitmapRasterBufferImpl : public RasterBuffer {
public:
- BitmapRasterBufferImpl(LayerTreeResourceProvider* resource_provider,
- const gfx::Size& size,
+ BitmapRasterBufferImpl(const gfx::Size& size,
const gfx::ColorSpace& color_space,
void* pixels,
uint64_t resource_content_id,
@@ -73,10 +85,8 @@ class BitmapRasterBufferImpl : public RasterBuffer {
} // namespace
BitmapRasterBufferProvider::BitmapRasterBufferProvider(
- LayerTreeResourceProvider* resource_provider,
- viz::SharedBitmapManager* shared_bitmap_manager)
- : resource_provider_(resource_provider),
- shared_bitmap_manager_(shared_bitmap_manager) {}
+ LayerTreeFrameSink* frame_sink)
+ : frame_sink_(frame_sink) {}
BitmapRasterBufferProvider::~BitmapRasterBufferProvider() = default;
@@ -89,16 +99,27 @@ BitmapRasterBufferProvider::AcquireBufferForRaster(
const gfx::Size& size = resource.size();
const gfx::ColorSpace& color_space = resource.color_space();
- if (!resource.shared_bitmap()) {
- // Allocate a backing that can be shared out of process to the display
- // compositor, and give ownership to the ResourcePool.
- resource.set_shared_bitmap(
- shared_bitmap_manager_->AllocateSharedBitmap(size));
+ if (!resource.software_backing()) {
+ auto backing = std::make_unique<BitmapSoftwareBacking>();
+ backing->frame_sink = frame_sink_;
+ backing->shared_bitmap_id = viz::SharedBitmap::GenerateId();
+ backing->shared_memory =
+ viz::bitmap_allocation::AllocateMappedBitmap(size, viz::RGBA_8888);
+
+ mojo::ScopedSharedBufferHandle handle =
+ viz::bitmap_allocation::DuplicateAndCloseMappedBitmap(
+ backing->shared_memory.get(), size, viz::RGBA_8888);
+ frame_sink_->DidAllocateSharedBitmap(std::move(handle),
+ backing->shared_bitmap_id);
+
+ resource.set_software_backing(std::move(backing));
}
+ BitmapSoftwareBacking* backing =
+ static_cast<BitmapSoftwareBacking*>(resource.software_backing());
return std::make_unique<BitmapRasterBufferImpl>(
- resource_provider_, size, color_space, resource.shared_bitmap()->pixels(),
- resource_content_id, previous_content_id);
+ size, color_space, backing->shared_memory->memory(), resource_content_id,
+ previous_content_id);
}
void BitmapRasterBufferProvider::Flush() {}
@@ -114,6 +135,11 @@ bool BitmapRasterBufferProvider::IsResourceSwizzleRequired(
return ResourceFormatRequiresSwizzle(viz::RGBA_8888);
}
+bool BitmapRasterBufferProvider::IsResourcePremultiplied(
+ bool must_support_alpha) const {
+ return true;
+}
+
bool BitmapRasterBufferProvider::CanPartialRasterIntoProvidedResource() const {
return true;
}
diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.h b/chromium/cc/raster/bitmap_raster_buffer_provider.h
index fbf774df995..1f33b863b5b 100644
--- a/chromium/cc/raster/bitmap_raster_buffer_provider.h
+++ b/chromium/cc/raster/bitmap_raster_buffer_provider.h
@@ -17,19 +17,14 @@ class ConvertableToTraceFormat;
}
}
-namespace viz {
-class SharedBitmapManager;
-}
-
namespace cc {
-class LayerTreeResourceProvider;
+class LayerTreeFrameSink;
class CC_EXPORT BitmapRasterBufferProvider : public RasterBufferProvider {
public:
~BitmapRasterBufferProvider() override;
- BitmapRasterBufferProvider(LayerTreeResourceProvider* resource_provider,
- viz::SharedBitmapManager* shared_bitmap_manager);
+ explicit BitmapRasterBufferProvider(LayerTreeFrameSink* frame_sink);
// Overridden from RasterBufferProvider:
std::unique_ptr<RasterBuffer> AcquireBufferForRaster(
@@ -39,6 +34,7 @@ class CC_EXPORT BitmapRasterBufferProvider : public RasterBufferProvider {
void Flush() override;
viz::ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
+ bool IsResourcePremultiplied(bool must_support_alpha) const override;
bool CanPartialRasterIntoProvidedResource() const override;
bool IsResourceReadyToDraw(
const ResourcePool::InUsePoolResource& resource) const override;
@@ -52,8 +48,7 @@ class CC_EXPORT BitmapRasterBufferProvider : public RasterBufferProvider {
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
const;
- LayerTreeResourceProvider* const resource_provider_;
- viz::SharedBitmapManager* const shared_bitmap_manager_;
+ LayerTreeFrameSink* const frame_sink_;
DISALLOW_COPY_AND_ASSIGN(BitmapRasterBufferProvider);
};
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc
index 43fca42ba7c..ba2abde1adc 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.cc
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc
@@ -9,7 +9,6 @@
#include <algorithm>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/histograms.h"
@@ -28,6 +27,7 @@
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
+#include "skia/ext/texture_handle.h"
#include "third_party/skia/include/core/SkMultiPictureDraw.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -38,6 +38,72 @@
namespace cc {
namespace {
+class ScopedSkSurfaceForUnpremultiplyAndDither {
+ public:
+ ScopedSkSurfaceForUnpremultiplyAndDither(
+ viz::RasterContextProvider* context_provider,
+ const gfx::Rect& playback_rect,
+ const gfx::Rect& raster_full_rect,
+ const gfx::Size& max_tile_size,
+ GLuint texture_id,
+ const gfx::Size& texture_size,
+ bool can_use_lcd_text,
+ int msaa_sample_count)
+ : context_provider_(context_provider),
+ texture_id_(texture_id),
+ offset_(playback_rect.OffsetFromOrigin() -
+ raster_full_rect.OffsetFromOrigin()),
+ size_(playback_rect.size()) {
+ // Determine the |intermediate_size| to use for our 32-bit texture. If we
+ // know the max tile size, use that. This prevents GPU cache explosion due
+ // to using lots of different 32-bit texture sizes. Otherwise just use the
+ // exact size of the target texture.
+ gfx::Size intermediate_size;
+ if (!max_tile_size.IsEmpty()) {
+ DCHECK_GE(max_tile_size.width(), texture_size.width());
+ DCHECK_GE(max_tile_size.height(), texture_size.height());
+ intermediate_size = max_tile_size;
+ } else {
+ intermediate_size = texture_size;
+ }
+
+ // Allocate a 32-bit surface for raster. We will copy from that into our
+ // actual surface in destruction.
+ SkImageInfo n32Info = SkImageInfo::MakeN32Premul(
+ intermediate_size.width(), intermediate_size.height());
+ SkSurfaceProps surface_props =
+ LayerTreeResourceProvider::ScopedSkSurface::ComputeSurfaceProps(
+ can_use_lcd_text);
+ surface_ = SkSurface::MakeRenderTarget(
+ context_provider->GrContext(), SkBudgeted::kNo, n32Info,
+ msaa_sample_count, kTopLeft_GrSurfaceOrigin, &surface_props);
+ }
+
+ ~ScopedSkSurfaceForUnpremultiplyAndDither() {
+ // In lost-context cases, |surface_| may be null and there's nothing
+ // meaningful to do here.
+ if (!surface_)
+ return;
+
+ GrBackendObject handle =
+ surface_->getTextureHandle(SkSurface::kFlushRead_BackendHandleAccess);
+ const GrGLTextureInfo* info =
+ skia::GrBackendObjectToGrGLTextureInfo(handle);
+ context_provider_->ContextGL()->UnpremultiplyAndDitherCopyCHROMIUM(
+ info->fID, texture_id_, offset_.x(), offset_.y(), size_.width(),
+ size_.height());
+ }
+
+ SkSurface* surface() { return surface_.get(); }
+
+ private:
+ viz::RasterContextProvider* context_provider_;
+ GLuint texture_id_;
+ gfx::Vector2d offset_;
+ gfx::Size size_;
+ sk_sp<SkSurface> surface_;
+};
+
static void RasterizeSourceOOP(
const RasterSource* raster_source,
bool resource_has_previous_content,
@@ -53,10 +119,11 @@ static void RasterizeSourceOOP(
const gfx::AxisTransform2d& transform,
const RasterSource::PlaybackSettings& playback_settings,
viz::RasterContextProvider* context_provider,
- bool use_distance_field_text,
int msaa_sample_count) {
gpu::raster::RasterInterface* ri = context_provider->RasterInterface();
- GLuint texture_id = ri->CreateAndConsumeTextureCHROMIUM(mailbox.name);
+ GLuint texture_id = ri->CreateAndConsumeTexture(
+ texture_is_overlay_candidate, gfx::BufferUsage::SCANOUT, resource_format,
+ mailbox.name);
if (!texture_storage_allocated) {
viz::TextureAllocation alloc = {texture_id, texture_target,
texture_is_overlay_candidate};
@@ -69,7 +136,7 @@ static void RasterizeSourceOOP(
// use GL_TEXTURE_2D.
ri->BeginRasterCHROMIUM(
texture_id, raster_source->background_color(), msaa_sample_count,
- playback_settings.use_lcd_text, use_distance_field_text,
+ playback_settings.use_lcd_text,
viz::ResourceFormatToClosestSkColorType(resource_format),
playback_settings.raster_color_space);
float recording_to_raster_scale =
@@ -85,6 +152,9 @@ static void RasterizeSourceOOP(
raster_source->requires_clear());
ri->EndRasterCHROMIUM();
+ // TODO(ericrk): Handle unpremultiply+dither for 4444 cases.
+ // https://crbug.com/789153
+
ri->DeleteTextures(1, &texture_id);
}
@@ -96,9 +166,6 @@ class ScopedGrContextAccess {
: context_provider_(context_provider) {
gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
ri->BeginGpuRaster();
-
- class GrContext* gr_context = context_provider_->GrContext();
- gr_context->resetContext();
}
~ScopedGrContextAccess() {
gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
@@ -124,12 +191,13 @@ static void RasterizeSource(
const gfx::AxisTransform2d& transform,
const RasterSource::PlaybackSettings& playback_settings,
viz::RasterContextProvider* context_provider,
- bool use_distance_field_text,
- int msaa_sample_count) {
- ScopedGrContextAccess gr_context_access(context_provider);
-
+ int msaa_sample_count,
+ bool unpremultiply_and_dither,
+ const gfx::Size& max_tile_size) {
gpu::raster::RasterInterface* ri = context_provider->RasterInterface();
- GLuint texture_id = ri->CreateAndConsumeTextureCHROMIUM(mailbox.name);
+ GLuint texture_id = ri->CreateAndConsumeTexture(
+ texture_is_overlay_candidate, gfx::BufferUsage::SCANOUT, resource_format,
+ mailbox.name);
if (!texture_storage_allocated) {
viz::TextureAllocation alloc = {texture_id, texture_target,
texture_is_overlay_candidate};
@@ -139,12 +207,23 @@ static void RasterizeSource(
}
{
- LayerTreeResourceProvider::ScopedSkSurface scoped_surface(
- context_provider->GrContext(), texture_id, texture_target,
- resource_size, resource_format, use_distance_field_text,
- playback_settings.use_lcd_text, msaa_sample_count);
-
- SkSurface* surface = scoped_surface.surface();
+ ScopedGrContextAccess gr_context_access(context_provider);
+ base::Optional<LayerTreeResourceProvider::ScopedSkSurface> scoped_surface;
+ base::Optional<ScopedSkSurfaceForUnpremultiplyAndDither>
+ scoped_dither_surface;
+ SkSurface* surface;
+ if (!unpremultiply_and_dither) {
+ scoped_surface.emplace(context_provider->GrContext(), texture_id,
+ texture_target, resource_size, resource_format,
+ playback_settings.use_lcd_text, msaa_sample_count);
+ surface = scoped_surface->surface();
+ } else {
+ scoped_dither_surface.emplace(
+ context_provider, playback_rect, raster_full_rect, max_tile_size,
+ texture_id, resource_size, playback_settings.use_lcd_text,
+ msaa_sample_count);
+ surface = scoped_dither_surface->surface();
+ }
// Allocating an SkSurface will fail after a lost context. Pretend we
// rasterized, as the contents of the resource don't matter anymore.
@@ -208,7 +287,6 @@ GpuRasterBufferProvider::RasterBufferImpl::RasterBufferImpl(
GpuRasterBufferProvider* client,
const ResourcePool::InUsePoolResource& in_use_resource,
GpuRasterBacking* backing,
- const gpu::SyncToken& before_raster_sync_token,
bool resource_has_previous_content)
: client_(client),
backing_(backing),
@@ -216,7 +294,7 @@ GpuRasterBufferProvider::RasterBufferImpl::RasterBufferImpl(
resource_format_(in_use_resource.format()),
color_space_(in_use_resource.color_space()),
resource_has_previous_content_(resource_has_previous_content),
- before_raster_sync_token_(before_raster_sync_token),
+ before_raster_sync_token_(backing->returned_sync_token),
mailbox_(backing->mailbox),
texture_target_(backing->texture_target),
texture_is_overlay_candidate_(backing->overlay_candidate),
@@ -259,18 +337,21 @@ GpuRasterBufferProvider::GpuRasterBufferProvider(
viz::ContextProvider* compositor_context_provider,
viz::RasterContextProvider* worker_context_provider,
LayerTreeResourceProvider* resource_provider,
- bool use_distance_field_text,
bool use_gpu_memory_buffer_resources,
int gpu_rasterization_msaa_sample_count,
viz::ResourceFormat preferred_tile_format,
+ const gfx::Size& max_tile_size,
+ bool unpremultiply_and_dither_low_bit_depth_tiles,
bool enable_oop_rasterization)
: compositor_context_provider_(compositor_context_provider),
worker_context_provider_(worker_context_provider),
resource_provider_(resource_provider),
- use_distance_field_text_(use_distance_field_text),
use_gpu_memory_buffer_resources_(use_gpu_memory_buffer_resources),
msaa_sample_count_(gpu_rasterization_msaa_sample_count),
preferred_tile_format_(preferred_tile_format),
+ max_tile_size_(max_tile_size),
+ unpremultiply_and_dither_low_bit_depth_tiles_(
+ unpremultiply_and_dither_low_bit_depth_tiles),
enable_oop_rasterization_(enable_oop_rasterization) {
DCHECK(compositor_context_provider);
DCHECK(worker_context_provider);
@@ -283,8 +364,6 @@ std::unique_ptr<RasterBuffer> GpuRasterBufferProvider::AcquireBufferForRaster(
const ResourcePool::InUsePoolResource& resource,
uint64_t resource_content_id,
uint64_t previous_content_id) {
- gpu::SyncToken before_raster_sync_token;
- bool new_resource = false;
if (!resource.gpu_backing()) {
auto backing = std::make_unique<GpuRasterBacking>();
backing->compositor_context_provider = compositor_context_provider_;
@@ -301,21 +380,18 @@ std::unique_ptr<RasterBuffer> GpuRasterBufferProvider::AcquireBufferForRaster(
backing->mailbox = gpu::Mailbox::Generate();
gl->ProduceTextureDirectCHROMIUM(backing->texture_id,
backing->mailbox.name);
- before_raster_sync_token =
+ // 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);
resource.set_gpu_backing(std::move(backing));
- new_resource = true;
}
GpuRasterBacking* backing =
static_cast<GpuRasterBacking*>(resource.gpu_backing());
- if (!new_resource)
- before_raster_sync_token = backing->returned_sync_token;
-
bool resource_has_previous_content =
resource_content_id && resource_content_id == previous_content_id;
return std::make_unique<RasterBufferImpl>(this, resource, backing,
- before_raster_sync_token,
resource_has_previous_content);
}
@@ -341,6 +417,12 @@ bool GpuRasterBufferProvider::IsResourceSwizzleRequired(
return false;
}
+bool GpuRasterBufferProvider::IsResourcePremultiplied(
+ bool must_support_alpha) const {
+ return !ShouldUnpremultiplyAndDitherResource(
+ GetResourceFormat(must_support_alpha));
+}
+
bool GpuRasterBufferProvider::CanPartialRasterIntoProvidedResource() const {
// Partial raster doesn't support MSAA, as the MSAA resolve is unaware of clip
// rects.
@@ -438,23 +520,34 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThread(
}
if (enable_oop_rasterization_) {
- RasterizeSourceOOP(
+ RasterizeSourceOOP(raster_source, resource_has_previous_content, mailbox,
+ texture_target, texture_is_overlay_candidate,
+ texture_storage_allocated, resource_size,
+ resource_format, color_space, raster_full_rect,
+ playback_rect, transform, playback_settings,
+ worker_context_provider_, msaa_sample_count_);
+ } else {
+ RasterizeSource(
raster_source, resource_has_previous_content, mailbox, texture_target,
texture_is_overlay_candidate, texture_storage_allocated, resource_size,
resource_format, color_space, raster_full_rect, playback_rect,
transform, playback_settings, worker_context_provider_,
- use_distance_field_text_, msaa_sample_count_);
- } else {
- RasterizeSource(raster_source, resource_has_previous_content, mailbox,
- texture_target, texture_is_overlay_candidate,
- texture_storage_allocated, resource_size, resource_format,
- color_space, raster_full_rect, playback_rect, transform,
- playback_settings, worker_context_provider_,
- use_distance_field_text_, msaa_sample_count_);
+ msaa_sample_count_,
+ ShouldUnpremultiplyAndDitherResource(resource_format), max_tile_size_);
}
// Generate sync token for cross context synchronization.
return LayerTreeResourceProvider::GenerateSyncTokenHelper(ri);
}
+bool GpuRasterBufferProvider::ShouldUnpremultiplyAndDitherResource(
+ viz::ResourceFormat format) const {
+ switch (format) {
+ case viz::RGBA_4444:
+ return unpremultiply_and_dither_low_bit_depth_tiles_;
+ default:
+ return false;
+ }
+}
+
} // namespace cc
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.h b/chromium/cc/raster/gpu_raster_buffer_provider.h
index 18a5ec6a6ad..c019d77fa07 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.h
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.h
@@ -24,10 +24,11 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
GpuRasterBufferProvider(viz::ContextProvider* compositor_context_provider,
viz::RasterContextProvider* worker_context_provider,
LayerTreeResourceProvider* resource_provider,
- bool use_distance_field_text,
bool use_gpu_memory_buffer_resources,
int gpu_rasterization_msaa_sample_count,
viz::ResourceFormat preferred_tile_format,
+ const gfx::Size& max_tile_size,
+ bool unpremultiply_and_dither_low_bit_depth_tiles,
bool enable_oop_rasterization);
~GpuRasterBufferProvider() override;
@@ -39,6 +40,7 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
void Flush() override;
viz::ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
+ bool IsResourcePremultiplied(bool must_support_alpha) const override;
bool CanPartialRasterIntoProvidedResource() const override;
bool IsResourceReadyToDraw(
const ResourcePool::InUsePoolResource& resource) const override;
@@ -73,7 +75,6 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
RasterBufferImpl(GpuRasterBufferProvider* client,
const ResourcePool::InUsePoolResource& in_use_resource,
GpuRasterBacking* backing,
- const gpu::SyncToken& before_raster_sync_token,
bool resource_has_previous_content);
~RasterBufferImpl() override;
@@ -109,13 +110,16 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
};
+ bool ShouldUnpremultiplyAndDitherResource(viz::ResourceFormat format) const;
+
viz::ContextProvider* const compositor_context_provider_;
viz::RasterContextProvider* const worker_context_provider_;
LayerTreeResourceProvider* const resource_provider_;
- const bool use_distance_field_text_;
const bool use_gpu_memory_buffer_resources_;
const int msaa_sample_count_;
const viz::ResourceFormat preferred_tile_format_;
+ const gfx::Size max_tile_size_;
+ const bool unpremultiply_and_dither_low_bit_depth_tiles_;
const bool enable_oop_rasterization_;
DISALLOW_COPY_AND_ASSIGN(GpuRasterBufferProvider);
diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.cc b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
index 872e159d8b6..fdf03d5db1d 100644
--- a/chromium/cc/raster/one_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
@@ -11,17 +11,16 @@
#include <utility>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/histograms.h"
#include "cc/base/math_util.h"
-#include "cc/resources/resource_util.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"
#include "components/viz/common/resources/platform_color.h"
#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/resources/resource_sizes.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -78,7 +77,6 @@ OneCopyRasterBufferProvider::RasterBufferImpl::RasterBufferImpl(
LayerTreeResourceProvider* resource_provider,
const ResourcePool::InUsePoolResource& in_use_resource,
OneCopyGpuBacking* backing,
- const gpu::SyncToken& before_raster_sync_token,
uint64_t previous_content_id)
: client_(client),
backing_(backing),
@@ -86,7 +84,7 @@ OneCopyRasterBufferProvider::RasterBufferImpl::RasterBufferImpl(
resource_format_(in_use_resource.format()),
color_space_(in_use_resource.color_space()),
previous_content_id_(previous_content_id),
- before_raster_sync_token_(before_raster_sync_token),
+ before_raster_sync_token_(backing->returned_sync_token),
mailbox_(backing->mailbox),
mailbox_texture_target_(backing->texture_target),
mailbox_texture_is_overlay_candidate_(backing->overlay_candidate),
@@ -156,16 +154,13 @@ OneCopyRasterBufferProvider::OneCopyRasterBufferProvider(
DCHECK(worker_context_provider);
}
-OneCopyRasterBufferProvider::~OneCopyRasterBufferProvider() {
-}
+OneCopyRasterBufferProvider::~OneCopyRasterBufferProvider() {}
std::unique_ptr<RasterBuffer>
OneCopyRasterBufferProvider::AcquireBufferForRaster(
const ResourcePool::InUsePoolResource& resource,
uint64_t resource_content_id,
uint64_t previous_content_id) {
- gpu::SyncToken before_raster_sync_token;
- bool new_resource = false;
if (!resource.gpu_backing()) {
auto backing = std::make_unique<OneCopyGpuBacking>();
backing->compositor_context_provider = compositor_context_provider_;
@@ -182,22 +177,19 @@ OneCopyRasterBufferProvider::AcquireBufferForRaster(
backing->mailbox = gpu::Mailbox::Generate();
gl->ProduceTextureDirectCHROMIUM(backing->texture_id,
backing->mailbox.name);
- before_raster_sync_token =
+ // 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);
resource.set_gpu_backing(std::move(backing));
- new_resource = true;
}
OneCopyGpuBacking* backing =
static_cast<OneCopyGpuBacking*>(resource.gpu_backing());
- if (!new_resource)
- before_raster_sync_token = backing->returned_sync_token;
-
// TODO(danakj): If resource_content_id != 0, we only need to copy/upload
// the dirty rect.
return std::make_unique<RasterBufferImpl>(this, resource_provider_, resource,
- backing, before_raster_sync_token,
- previous_content_id);
+ backing, previous_content_id);
}
void OneCopyRasterBufferProvider::Flush() {
@@ -225,6 +217,13 @@ bool OneCopyRasterBufferProvider::IsResourceSwizzleRequired(
return ResourceFormatRequiresSwizzle(GetResourceFormat(must_support_alpha));
}
+bool OneCopyRasterBufferProvider::IsResourcePremultiplied(
+ bool must_support_alpha) const {
+ // TODO(ericrk): Handle unpremultiply/dither in one-copy case as well.
+ // https://crbug.com/789153
+ return true;
+}
+
bool OneCopyRasterBufferProvider::CanPartialRasterIntoProvidedResource() const {
// While OneCopyRasterBufferProvider has an internal partial raster
// implementation, it cannot directly partial raster into the externally
@@ -392,7 +391,10 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread(
// making the mailbox. This ensures that the mailbox we consume here is valid
// by the time the consume command executes.
ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
- GLuint mailbox_texture_id = ri->CreateAndConsumeTextureCHROMIUM(mailbox.name);
+ GLuint mailbox_texture_id = ri->CreateAndConsumeTexture(
+ mailbox_texture_is_overlay_candidate, gfx::BufferUsage::SCANOUT,
+ resource_format, mailbox.name);
+
if (!mailbox_texture_storage_allocated) {
viz::TextureAllocation alloc = {mailbox_texture_id, mailbox_texture_target,
mailbox_texture_is_overlay_candidate};
@@ -401,20 +403,18 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread(
resource_size, alloc, color_space);
}
- GLenum image_target = resource_provider_->GetImageTextureTarget(
- worker_context_provider_->ContextCapabilities(), StagingBufferUsage(),
- staging_buffer->format);
-
// Create and bind staging texture.
if (!staging_buffer->texture_id) {
- ri->GenTextures(1, &staging_buffer->texture_id);
- ri->BindTexture(image_target, staging_buffer->texture_id);
- ri->TexParameteri(image_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- ri->TexParameteri(image_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- ri->TexParameteri(image_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- ri->TexParameteri(image_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- } else {
- ri->BindTexture(image_target, staging_buffer->texture_id);
+ staging_buffer->texture_id =
+ ri->CreateTexture(true, StagingBufferUsage(), staging_buffer->format);
+ ri->TexParameteri(staging_buffer->texture_id, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ ri->TexParameteri(staging_buffer->texture_id, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ ri->TexParameteri(staging_buffer->texture_id, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ ri->TexParameteri(staging_buffer->texture_id, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
}
// Create and bind image.
@@ -424,15 +424,19 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread(
staging_buffer->gpu_memory_buffer->AsClientBuffer(),
staging_buffer->size.width(), staging_buffer->size.height(),
GLInternalFormat(staging_buffer->format));
- ri->BindTexImage2DCHROMIUM(image_target, staging_buffer->image_id);
+ ri->BindTexImage2DCHROMIUM(staging_buffer->texture_id,
+ staging_buffer->image_id);
}
} else {
- ri->ReleaseTexImage2DCHROMIUM(image_target, staging_buffer->image_id);
- ri->BindTexImage2DCHROMIUM(image_target, staging_buffer->image_id);
+ ri->ReleaseTexImage2DCHROMIUM(staging_buffer->texture_id,
+ staging_buffer->image_id);
+ ri->BindTexImage2DCHROMIUM(staging_buffer->texture_id,
+ staging_buffer->image_id);
}
// Unbind staging texture.
- ri->BindTexture(image_target, 0);
+ // TODO(vmiura): Need a way to ensure we don't hold onto bindings?
+ // ri->BindTexture(image_target, 0);
if (resource_provider_->use_sync_query()) {
if (!staging_buffer->query_id)
@@ -453,7 +457,7 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread(
ri->CompressedCopyTextureCHROMIUM(staging_buffer->texture_id,
mailbox_texture_id);
} else {
- int bytes_per_row = ResourceUtil::UncheckedWidthInBytes<int>(
+ int bytes_per_row = viz::ResourceSizes::UncheckedWidthInBytes<int>(
rect_to_copy.width(), staging_buffer->format);
int chunk_size_in_rows =
std::max(1, max_bytes_per_copy_operation_ / bytes_per_row);
@@ -466,10 +470,8 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread(
int rows_to_copy = std::min(chunk_size_in_rows, height - y);
DCHECK_GT(rows_to_copy, 0);
- ri->CopySubTextureCHROMIUM(staging_buffer->texture_id, 0,
- mailbox_texture_target, mailbox_texture_id, 0,
- 0, y, 0, y, rect_to_copy.width(), rows_to_copy,
- false, false, false);
+ ri->CopySubTexture(staging_buffer->texture_id, mailbox_texture_id, 0, y,
+ 0, y, rect_to_copy.width(), rows_to_copy);
y += rows_to_copy;
// Increment |bytes_scheduled_since_last_flush_| by the amount of memory
diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.h b/chromium/cc/raster/one_copy_raster_buffer_provider.h
index d1408d13004..7e1fac1bab7 100644
--- a/chromium/cc/raster/one_copy_raster_buffer_provider.h
+++ b/chromium/cc/raster/one_copy_raster_buffer_provider.h
@@ -44,6 +44,7 @@ class CC_EXPORT OneCopyRasterBufferProvider : public RasterBufferProvider {
void Flush() override;
viz::ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
+ bool IsResourcePremultiplied(bool must_support_alpha) const override;
bool CanPartialRasterIntoProvidedResource() const override;
bool IsResourceReadyToDraw(
const ResourcePool::InUsePoolResource& resource) const override;
@@ -80,7 +81,6 @@ class CC_EXPORT OneCopyRasterBufferProvider : public RasterBufferProvider {
LayerTreeResourceProvider* resource_provider,
const ResourcePool::InUsePoolResource& in_use_resource,
OneCopyGpuBacking* backing,
- const gpu::SyncToken& before_raster_sync_token,
uint64_t previous_content_id);
~RasterBufferImpl() override;
diff --git a/chromium/cc/raster/playback_image_provider.cc b/chromium/cc/raster/playback_image_provider.cc
index 557b421bbae..75d8ddf0608 100644
--- a/chromium/cc/raster/playback_image_provider.cc
+++ b/chromium/cc/raster/playback_image_provider.cc
@@ -4,7 +4,6 @@
#include "cc/raster/playback_image_provider.h"
-#include "base/memory/ptr_util.h"
#include "cc/tiles/image_decode_cache.h"
namespace cc {
@@ -20,7 +19,7 @@ void UnrefImageFromCache(DrawImage draw_image,
PlaybackImageProvider::PlaybackImageProvider(
ImageDecodeCache* cache,
const gfx::ColorSpace& target_color_space,
- base::Optional<Settings> settings)
+ base::Optional<Settings>&& settings)
: cache_(cache),
target_color_space_(target_color_space),
settings_(std::move(settings)) {
@@ -70,7 +69,10 @@ PlaybackImageProvider::GetDecodedDrawImage(const DrawImage& draw_image) {
}
PlaybackImageProvider::Settings::Settings() = default;
-PlaybackImageProvider::Settings::Settings(const Settings& other) = default;
+PlaybackImageProvider::Settings::Settings(PlaybackImageProvider::Settings&&) =
+ default;
PlaybackImageProvider::Settings::~Settings() = default;
+PlaybackImageProvider::Settings& PlaybackImageProvider::Settings::operator=(
+ PlaybackImageProvider::Settings&&) = default;
} // namespace cc
diff --git a/chromium/cc/raster/playback_image_provider.h b/chromium/cc/raster/playback_image_provider.h
index 67974f3f341..a33092d2b5b 100644
--- a/chromium/cc/raster/playback_image_provider.h
+++ b/chromium/cc/raster/playback_image_provider.h
@@ -20,8 +20,10 @@ class CC_EXPORT PlaybackImageProvider : public ImageProvider {
public:
struct CC_EXPORT Settings {
Settings();
- Settings(const Settings& other);
+ Settings(const Settings&) = delete;
+ Settings(Settings&&);
~Settings();
+ Settings& operator=(Settings&&);
// The set of image ids to skip during raster.
PaintImageIdFlatSet images_to_skip;
@@ -34,7 +36,7 @@ class CC_EXPORT PlaybackImageProvider : public ImageProvider {
// If no settings are provided, all images are skipped during rasterization.
PlaybackImageProvider(ImageDecodeCache* cache,
const gfx::ColorSpace& target_color_space,
- base::Optional<Settings> settings);
+ base::Optional<Settings>&& settings);
~PlaybackImageProvider() override;
PlaybackImageProvider(PlaybackImageProvider&& other);
diff --git a/chromium/cc/raster/playback_image_provider_unittest.cc b/chromium/cc/raster/playback_image_provider_unittest.cc
index 0206999d6e4..40036e87032 100644
--- a/chromium/cc/raster/playback_image_provider_unittest.cc
+++ b/chromium/cc/raster/playback_image_provider_unittest.cc
@@ -85,7 +85,8 @@ TEST(PlaybackImageProviderTest, SkipsSomeImages) {
settings.emplace();
settings->images_to_skip = {skip_image.stable_id()};
- PlaybackImageProvider provider(&cache, gfx::ColorSpace(), settings);
+ PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+ std::move(settings));
SkIRect rect = SkIRect::MakeWH(10, 10);
SkMatrix matrix = SkMatrix::I();
@@ -99,7 +100,8 @@ TEST(PlaybackImageProviderTest, RefAndUnrefDecode) {
base::Optional<PlaybackImageProvider::Settings> settings;
settings.emplace();
- PlaybackImageProvider provider(&cache, gfx::ColorSpace(), settings);
+ PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+ std::move(settings));
{
SkRect rect = SkRect::MakeWH(10, 10);
@@ -127,7 +129,8 @@ TEST(PlaybackImageProviderTest, SwapsGivenFrames) {
settings.emplace();
settings->image_to_current_frame_index = image_to_frame;
- PlaybackImageProvider provider(&cache, gfx::ColorSpace(), settings);
+ PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+ std::move(settings));
SkIRect rect = SkIRect::MakeWH(10, 10);
SkMatrix matrix = SkMatrix::I();
@@ -143,7 +146,8 @@ TEST(PlaybackImageProviderTest, BitmapImages) {
base::Optional<PlaybackImageProvider::Settings> settings;
settings.emplace();
- PlaybackImageProvider provider(&cache, gfx::ColorSpace(), settings);
+ PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+ std::move(settings));
{
SkIRect rect = SkIRect::MakeWH(10, 10);
@@ -174,7 +178,8 @@ TEST(PlaybackImageProviderTest, TextureImages) {
MockDecodeCache cache;
base::Optional<PlaybackImageProvider::Settings> settings;
settings.emplace();
- PlaybackImageProvider provider(&cache, gfx::ColorSpace(), settings);
+ PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+ std::move(settings));
{
SkIRect rect = SkIRect::MakeWH(10, 10);
SkMatrix matrix = SkMatrix::I();
diff --git a/chromium/cc/raster/raster_buffer_provider.h b/chromium/cc/raster/raster_buffer_provider.h
index c25f2e91409..12b7e0d80da 100644
--- a/chromium/cc/raster/raster_buffer_provider.h
+++ b/chromium/cc/raster/raster_buffer_provider.h
@@ -62,6 +62,9 @@ class CC_EXPORT RasterBufferProvider {
// Determine if the resource requires swizzling.
virtual bool IsResourceSwizzleRequired(bool must_support_alpha) const = 0;
+ // Determines if the resource is premultiplied.
+ virtual bool IsResourcePremultiplied(bool must_support_alpha) const = 0;
+
// Determine if the RasterBufferProvider can handle partial raster into
// the Resource provided in AcquireBufferForRaster.
virtual bool CanPartialRasterIntoProvidedResource() const = 0;
diff --git a/chromium/cc/raster/raster_buffer_provider_perftest.cc b/chromium/cc/raster/raster_buffer_provider_perftest.cc
index 054183150de..4d96efeb552 100644
--- a/chromium/cc/raster/raster_buffer_provider_perftest.cc
+++ b/chromium/cc/raster/raster_buffer_provider_perftest.cc
@@ -6,7 +6,6 @@
#include <stdint.h>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/test/test_simple_task_runner.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -19,6 +18,7 @@
#include "cc/raster/zero_copy_raster_buffer_provider.h"
#include "cc/resources/resource_pool.h"
#include "cc/resources/resource_provider.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/common/gpu/context_cache_controller.h"
@@ -27,7 +27,6 @@
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_context_support.h"
#include "components/viz/test/test_gpu_memory_buffer_manager.h"
-#include "components/viz/test/test_shared_bitmap_manager.h"
#include "gpu/command_buffer/client/raster_implementation_gles.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/config/gpu_feature_info.h"
@@ -122,9 +121,6 @@ class PerfContextProvider
viz::ContextCacheController* CacheController() override {
return &cache_controller_;
}
- void InvalidateGrContext(uint32_t state) override {
- test_context_provider_->GrContext()->resetContext(state);
- }
base::Lock* GetLock() override { return &context_lock_; }
void AddObserver(viz::ContextLostObserver* obs) override {}
void RemoveObserver(viz::ContextLostObserver* obs) override {}
@@ -334,6 +330,7 @@ class RasterBufferProviderPerfTestBase {
protected:
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_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
std::unique_ptr<ResourcePool> resource_pool_;
@@ -378,8 +375,8 @@ class RasterBufferProviderPerfTest
Create3dResourceProvider();
raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>(
compositor_context_provider_.get(), worker_context_provider_.get(),
- resource_provider_.get(), false, false, 0,
- viz::PlatformColor::BestTextureFormat(), false);
+ resource_provider_.get(), false, 0,
+ viz::PlatformColor::BestTextureFormat(), gfx::Size(), true, false);
resource_pool_ = std::make_unique<ResourcePool>(
resource_provider_.get(), task_runner_,
ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kGpu,
@@ -388,7 +385,7 @@ class RasterBufferProviderPerfTest
case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
CreateSoftwareResourceProvider();
raster_buffer_provider_ = std::make_unique<BitmapRasterBufferProvider>(
- resource_provider_.get(), &shared_bitmap_manager_);
+ layer_tree_frame_sink_.get());
resource_pool_ = std::make_unique<ResourcePool>(
resource_provider_.get(), task_runner_,
ResourcePool::kDefaultExpirationDelay,
@@ -527,8 +524,9 @@ class RasterBufferProviderPerfTest
}
void CreateSoftwareResourceProvider() {
+ layer_tree_frame_sink_ = FakeLayerTreeFrameSink::CreateSoftware();
resource_provider_ = FakeResourceProvider::CreateLayerTreeResourceProvider(
- nullptr, &shared_bitmap_manager_, nullptr);
+ nullptr, layer_tree_frame_sink_->shared_bitmap_manager(), nullptr);
}
std::string TestModifierString() const {
@@ -549,7 +547,6 @@ class RasterBufferProviderPerfTest
std::unique_ptr<TileTaskManager> tile_task_manager_;
std::unique_ptr<RasterBufferProvider> raster_buffer_provider_;
viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
- viz::TestSharedBitmapManager shared_bitmap_manager_;
};
TEST_P(RasterBufferProviderPerfTest, ScheduleTasks) {
diff --git a/chromium/cc/raster/raster_buffer_provider_unittest.cc b/chromium/cc/raster/raster_buffer_provider_unittest.cc
index fdbe51e9b9a..4bc78099834 100644
--- a/chromium/cc/raster/raster_buffer_provider_unittest.cc
+++ b/chromium/cc/raster/raster_buffer_provider_unittest.cc
@@ -14,7 +14,6 @@
#include "base/cancelable_callback.h"
#include "base/location.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
@@ -28,6 +27,7 @@
#include "cc/raster/zero_copy_raster_buffer_provider.h"
#include "cc/resources/resource_pool.h"
#include "cc/resources/resource_provider.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"
@@ -180,8 +180,8 @@ class RasterBufferProviderTest
Create3dResourceProvider();
raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>(
context_provider_.get(), worker_context_provider_.get(),
- resource_provider_.get(), false, false, 0,
- viz::PlatformColor::BestTextureFormat(), false);
+ resource_provider_.get(), false, 0,
+ viz::PlatformColor::BestTextureFormat(), gfx::Size(), true, false);
pool_ = std::make_unique<ResourcePool>(
resource_provider_.get(), base::ThreadTaskRunnerHandle::Get(),
base::TimeDelta(), ResourcePool::Mode::kGpu, true);
@@ -189,7 +189,7 @@ class RasterBufferProviderTest
case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
CreateSoftwareResourceProvider();
raster_buffer_provider_ = std::make_unique<BitmapRasterBufferProvider>(
- resource_provider_.get(), &shared_bitmap_manager_);
+ layer_tree_frame_sink_.get());
pool_ = std::make_unique<ResourcePool>(
resource_provider_.get(), base::ThreadTaskRunnerHandle::Get(),
base::TimeDelta(), ResourcePool::Mode::kSoftware, true);
@@ -266,6 +266,15 @@ class RasterBufferProviderTest
resources_.push_back(std::move(resource));
}
+ void AppendTaskWithResource(unsigned id,
+ const ResourcePool::InUsePoolResource* resource) {
+ std::unique_ptr<RasterBuffer> raster_buffer =
+ raster_buffer_provider_->AcquireBufferForRaster(*resource, 0, 0);
+ TileTask::Vector empty;
+ tasks_.push_back(
+ new TestRasterTaskImpl(this, id, std::move(raster_buffer), &empty));
+ }
+
const std::vector<RasterTaskResult>& completed_tasks() const {
return completed_tasks_;
}
@@ -302,12 +311,14 @@ class RasterBufferProviderTest
viz::TestWebGraphicsContext3D* context3d =
context_provider_->TestContext3d();
context3d->set_support_sync_query(true);
+ layer_tree_frame_sink_ = FakeLayerTreeFrameSink::Create3d();
resource_provider_ = FakeResourceProvider::CreateLayerTreeResourceProvider(
context_provider_.get(), &shared_bitmap_manager_,
&gpu_memory_buffer_manager_);
}
void CreateSoftwareResourceProvider() {
+ layer_tree_frame_sink_ = FakeLayerTreeFrameSink::CreateSoftware();
resource_provider_ = FakeResourceProvider::CreateLayerTreeResourceProvider(
nullptr, &shared_bitmap_manager_, &gpu_memory_buffer_manager_);
}
@@ -321,6 +332,7 @@ class RasterBufferProviderTest
scoped_refptr<viz::TestContextProvider> context_provider_;
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<TileTaskManager> tile_task_manager_;
std::unique_ptr<RasterBufferProvider> raster_buffer_provider_;
@@ -453,6 +465,47 @@ TEST_P(RasterBufferProviderTest, ReadyToDrawCallbackNoDuplicate) {
EXPECT_TRUE(callback_id);
}
+TEST_P(RasterBufferProviderTest, WaitOnSyncTokenAfterReschedulingTask) {
+ if (GetParam() != RASTER_BUFFER_PROVIDER_TYPE_GPU &&
+ GetParam() != RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY)
+ return;
+
+ base::Lock lock;
+
+ // Schedule a task that is prevented from completing with a lock.
+ lock.Acquire();
+ AppendBlockingTask(0u, &lock);
+ ScheduleTasks();
+
+ EXPECT_EQ(resources_.size(), 1u);
+ const ResourcePool::InUsePoolResource* resource = &resources_[0];
+
+ // Schedule another task to replace the still-pending task using the same
+ // resource.
+ RasterTaskVector tasks;
+ tasks.swap(tasks_);
+ AppendTaskWithResource(1u, resource);
+ ScheduleTasks();
+
+ // The first task is canceled, but the second task uses the same resource, and
+ // waits on the compositor sync token that was left by the first task.
+ RunMessageLoopUntilAllTasksHaveCompleted();
+
+ {
+ viz::ContextProvider::ScopedContextLock context_lock(
+ worker_context_provider_.get());
+ viz::TestWebGraphicsContext3D* context3d =
+ worker_context_provider_->TestContext3d();
+ EXPECT_TRUE(context3d->last_waited_sync_token().HasData());
+ }
+
+ lock.Release();
+
+ ASSERT_EQ(completed_tasks().size(), 2u);
+ EXPECT_TRUE(completed_tasks()[0].canceled);
+ EXPECT_FALSE(completed_tasks()[1].canceled);
+}
+
INSTANTIATE_TEST_CASE_P(
RasterBufferProviderTests,
RasterBufferProviderTest,
diff --git a/chromium/cc/raster/raster_source.cc b/chromium/cc/raster/raster_source.cc
index 61d356f0690..be224fe6d8e 100644
--- a/chromium/cc/raster/raster_source.cc
+++ b/chromium/cc/raster/raster_source.cc
@@ -162,7 +162,8 @@ void RasterSource::PlaybackToCanvas(
void RasterSource::PlaybackToCanvas(SkCanvas* raster_canvas,
ImageProvider* image_provider) const {
- DCHECK(display_list_.get());
+ // TODO(enne): Temporary CHECK debugging for http://crbug.com/823835
+ CHECK(display_list_.get());
int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
for (int i = 0; i < repeat_count; ++i)
display_list_->Raster(raster_canvas, image_provider);
diff --git a/chromium/cc/raster/scoped_gpu_raster.cc b/chromium/cc/raster/scoped_gpu_raster.cc
index 9c0752ca1c6..3ba2be38286 100644
--- a/chromium/cc/raster/scoped_gpu_raster.cc
+++ b/chromium/cc/raster/scoped_gpu_raster.cc
@@ -3,7 +3,10 @@
// found in the LICENSE file.
#include "cc/raster/scoped_gpu_raster.h"
+
+#include "build/build_config.h"
#include "components/viz/common/gpu/context_provider.h"
+#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
@@ -30,8 +33,11 @@ void ScopedGpuRaster::BeginGpuRaster() {
// arguments even when tracing is disabled.
gl->TraceBeginCHROMIUM("ScopedGpuRaster", "GpuRasterization");
- class GrContext* gr_context = context_provider_->GrContext();
+#if defined(OS_ANDROID)
+ // TODO(crbug.com/832810): The following reset should not be necessary.
+ GrContext* gr_context = context_provider_->GrContext();
gr_context->resetContext();
+#endif
}
void ScopedGpuRaster::EndGpuRaster() {
diff --git a/chromium/cc/raster/staging_buffer_pool.cc b/chromium/cc/raster/staging_buffer_pool.cc
index 84ee9a31ada..37c39fc4102 100644
--- a/chromium/cc/raster/staging_buffer_pool.cc
+++ b/chromium/cc/raster/staging_buffer_pool.cc
@@ -7,13 +7,12 @@
#include <memory>
#include "base/memory/memory_coordinator_client_registry.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "cc/base/container_util.h"
-#include "cc/resources/resource_util.h"
#include "components/viz/common/gpu/raster_context_provider.h"
+#include "components/viz/common/resources/resource_sizes.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "ui/gfx/gpu_memory_buffer.h"
@@ -103,7 +102,7 @@ void StagingBuffer::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
MemoryAllocatorDump* buffer_dump = pmd->CreateAllocatorDump(buffer_dump_name);
uint64_t buffer_size_in_bytes =
- ResourceUtil::UncheckedSizeInBytes<uint64_t>(size, format);
+ viz::ResourceSizes::UncheckedSizeInBytes<uint64_t>(size, format);
buffer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes,
buffer_size_in_bytes);
@@ -210,8 +209,8 @@ void StagingBufferPool::AddStagingBuffer(const StagingBuffer* staging_buffer,
DCHECK(buffers_.find(staging_buffer) == buffers_.end());
buffers_.insert(staging_buffer);
- int buffer_usage_in_bytes =
- ResourceUtil::UncheckedSizeInBytes<int>(staging_buffer->size, format);
+ int buffer_usage_in_bytes = viz::ResourceSizes::UncheckedSizeInBytes<int>(
+ staging_buffer->size, format);
staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes;
}
@@ -221,7 +220,7 @@ void StagingBufferPool::RemoveStagingBuffer(
DCHECK(buffers_.find(staging_buffer) != buffers_.end());
buffers_.erase(staging_buffer);
- int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>(
+ int buffer_usage_in_bytes = viz::ResourceSizes::UncheckedSizeInBytes<int>(
staging_buffer->size, staging_buffer->format);
DCHECK_GE(staging_buffer_usage_in_bytes_, buffer_usage_in_bytes);
staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes;
@@ -231,7 +230,7 @@ void StagingBufferPool::MarkStagingBufferAsFree(
const StagingBuffer* staging_buffer) {
lock_.AssertAcquired();
- int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>(
+ int buffer_usage_in_bytes = viz::ResourceSizes::UncheckedSizeInBytes<int>(
staging_buffer->size, staging_buffer->format);
free_staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes;
}
@@ -240,7 +239,7 @@ void StagingBufferPool::MarkStagingBufferAsBusy(
const StagingBuffer* staging_buffer) {
lock_.AssertAcquired();
- int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>(
+ int buffer_usage_in_bytes = viz::ResourceSizes::UncheckedSizeInBytes<int>(
staging_buffer->size, staging_buffer->format);
DCHECK_GE(free_staging_buffer_usage_in_bytes_, buffer_usage_in_bytes);
free_staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes;
diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
index c3c6ec60692..9cefe8af99b 100644
--- a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
@@ -251,6 +251,11 @@ bool ZeroCopyRasterBufferProvider::IsResourceSwizzleRequired(
return ResourceFormatRequiresSwizzle(GetResourceFormat(must_support_alpha));
}
+bool ZeroCopyRasterBufferProvider::IsResourcePremultiplied(
+ bool must_support_alpha) const {
+ return true;
+}
+
bool ZeroCopyRasterBufferProvider::CanPartialRasterIntoProvidedResource()
const {
return false;
diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.h b/chromium/cc/raster/zero_copy_raster_buffer_provider.h
index 1c6c6ae7bbc..d7a118e2988 100644
--- a/chromium/cc/raster/zero_copy_raster_buffer_provider.h
+++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.h
@@ -42,6 +42,7 @@ class CC_EXPORT ZeroCopyRasterBufferProvider : public RasterBufferProvider {
void Flush() override;
viz::ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
+ bool IsResourcePremultiplied(bool must_support_alpha) const override;
bool CanPartialRasterIntoProvidedResource() const override;
bool IsResourceReadyToDraw(
const ResourcePool::InUsePoolResource& resource) const override;
diff --git a/chromium/cc/resources/cross_thread_shared_bitmap.cc b/chromium/cc/resources/cross_thread_shared_bitmap.cc
new file mode 100644
index 00000000000..642bd39d89e
--- /dev/null
+++ b/chromium/cc/resources/cross_thread_shared_bitmap.cc
@@ -0,0 +1,18 @@
+// 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/resources/cross_thread_shared_bitmap.h"
+
+namespace cc {
+
+CrossThreadSharedBitmap::CrossThreadSharedBitmap(
+ const viz::SharedBitmapId& id,
+ std::unique_ptr<base::SharedMemory> memory,
+ const gfx::Size& size,
+ viz::ResourceFormat format)
+ : id_(id), memory_(std::move(memory)), size_(size), format_(format) {}
+
+CrossThreadSharedBitmap::~CrossThreadSharedBitmap() = default;
+
+} // namespace cc
diff --git a/chromium/cc/resources/cross_thread_shared_bitmap.h b/chromium/cc/resources/cross_thread_shared_bitmap.h
new file mode 100644
index 00000000000..1a436e91b70
--- /dev/null
+++ b/chromium/cc/resources/cross_thread_shared_bitmap.h
@@ -0,0 +1,51 @@
+// 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_RESOURCES_CROSS_THREAD_SHARED_BITMAP_H_
+#define CC_RESOURCES_CROSS_THREAD_SHARED_BITMAP_H_
+
+#include <memory>
+
+#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 "ui/gfx/geometry/size.h"
+
+namespace cc {
+
+// This class holds ownership of a base::SharedMemory segment for use as a
+// composited resource, and is refcounted in order to share ownership with the
+// LayerTreeHost, via TextureLayer, which needs access to the base::SharedMemory
+// from the compositor thread.
+// Because all the fields exposed are const, they can be used from any thread
+// without conflict, as they only read existing states.
+class CC_EXPORT CrossThreadSharedBitmap
+ : public base::RefCountedThreadSafe<CrossThreadSharedBitmap> {
+ public:
+ CrossThreadSharedBitmap(const viz::SharedBitmapId& id,
+ std::unique_ptr<base::SharedMemory> memory,
+ const gfx::Size& size,
+ viz::ResourceFormat format);
+
+ const viz::SharedBitmapId& id() const { return id_; }
+ const base::SharedMemory* shared_memory() const { return memory_.get(); }
+ const gfx::Size& size() const { return size_; }
+ viz::ResourceFormat format() const { return format_; }
+
+ private:
+ friend base::RefCountedThreadSafe<CrossThreadSharedBitmap>;
+
+ ~CrossThreadSharedBitmap();
+
+ const viz::SharedBitmapId id_;
+ const std::unique_ptr<const base::SharedMemory> memory_;
+ const gfx::Size size_;
+ const viz::ResourceFormat format_;
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_CROSS_THREAD_SHARED_BITMAP_H_
diff --git a/chromium/cc/resources/display_resource_provider.cc b/chromium/cc/resources/display_resource_provider.cc
index fe60bcc9fea..c48d3ff6768 100644
--- a/chromium/cc/resources/display_resource_provider.cc
+++ b/chromium/cc/resources/display_resource_provider.cc
@@ -80,6 +80,12 @@ void DisplayResourceProvider::SendPromotionHints(
continue;
const viz::internal::Resource* resource = LockForRead(id);
+ // TODO(ericrk): We should never fail LockForRead, but we appear to be
+ // doing so on Android in rare cases. Handle this gracefully until a better
+ // solution can be found. https://crbug.com/811858
+ if (!resource)
+ return;
+
DCHECK(resource->wants_promotion_hint);
// Insist that this is backed by a GPU texture.
@@ -121,8 +127,11 @@ size_t DisplayResourceProvider::CountPromotionHintRequestsForTesting() {
#endif
bool DisplayResourceProvider::IsOverlayCandidate(viz::ResourceId id) {
- viz::internal::Resource* resource = GetResource(id);
- return resource->is_overlay_candidate;
+ viz::internal::Resource* resource = TryGetResource(id);
+ // TODO(ericrk): We should never fail TryGetResource, but we appear to
+ // be doing so on Android in rare cases. Handle this gracefully until a
+ // better solution can be found. https://crbug.com/811858
+ return resource && resource->is_overlay_candidate;
}
viz::ResourceType DisplayResourceProvider::GetResourceType(viz::ResourceId id) {
@@ -135,7 +144,12 @@ gfx::BufferFormat DisplayResourceProvider::GetBufferFormat(viz::ResourceId id) {
}
void DisplayResourceProvider::WaitSyncToken(viz::ResourceId id) {
- viz::internal::Resource* resource = GetResource(id);
+ viz::internal::Resource* resource = TryGetResource(id);
+ // TODO(ericrk): We should never fail TryGetResource, but we appear to
+ // be doing so on Android in rare cases. Handle this gracefully until a
+ // better solution can be found. https://crbug.com/811858
+ if (!resource)
+ return;
WaitSyncTokenInternal(resource);
#if defined(OS_ANDROID)
// Now that the resource is synced, we may send it a promotion hint. We could
@@ -254,7 +268,8 @@ void DisplayResourceProvider::DeleteAndReturnUnusedResourcesToChild(
bool is_lost = resource.lost ||
(resource.is_gpu_resource_type() && lost_context_provider_);
- if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
+ if (resource.exported_count > 0 || resource.lock_for_read_count > 0 ||
+ resource.locked_for_external_use) {
if (style != FOR_SHUTDOWN) {
// Defer this resource deletion.
resource.marked_for_deletion = true;
@@ -378,11 +393,12 @@ void DisplayResourceProvider::ReceiveFromChild(
viz::ResourceId local_id = next_id_++;
viz::internal::Resource* resource = nullptr;
if (it->is_software) {
+ DCHECK(IsBitmapFormatSupported(it->format));
resource = InsertResource(
local_id,
viz::internal::Resource(it->size, viz::internal::Resource::DELEGATED,
viz::ResourceTextureHint::kDefault,
- viz::ResourceType::kBitmap, viz::RGBA_8888,
+ viz::ResourceType::kBitmap, it->format,
it->color_space));
resource->has_shared_bitmap_id = true;
resource->shared_bitmap_id = it->mailbox_holder.mailbox;
@@ -452,7 +468,12 @@ GLenum DisplayResourceProvider::BindForSampling(viz::ResourceId resource_id,
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
GLES2Interface* gl = ContextGL();
ResourceMap::iterator it = resources_.find(resource_id);
- DCHECK(it != resources_.end());
+ // TODO(ericrk): We should never fail to find resource_id, but we appear to
+ // be doing so on Android in rare cases. Handle this gracefully until a
+ // better solution can be found. https://crbug.com/811858
+ if (it == resources_.end())
+ return GL_TEXTURE_2D;
+
viz::internal::Resource* resource = &it->second;
DCHECK(resource->lock_for_read_count);
// TODO(xing.xu): remove locked_for_write.
@@ -492,7 +513,8 @@ GLenum DisplayResourceProvider::BindForSampling(viz::ResourceId resource_id,
bool DisplayResourceProvider::InUse(viz::ResourceId id) {
viz::internal::Resource* resource = GetResource(id);
- return resource->lock_for_read_count > 0 || resource->lost;
+ return resource->lock_for_read_count > 0 || resource->lost ||
+ resource->locked_for_external_use;
}
DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
@@ -501,6 +523,12 @@ DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
: resource_provider_(resource_provider), resource_id_(resource_id) {
const viz::internal::Resource* resource =
resource_provider->LockForRead(resource_id);
+ // TODO(ericrk): We should never fail LockForRead, but we appear to be
+ // doing so on Android in rare cases. Handle this gracefully until a better
+ // solution can be found. https://crbug.com/811858
+ if (!resource)
+ return;
+
texture_id_ = resource->gl_id;
target_ = resource->target;
size_ = resource->size;
@@ -509,7 +537,13 @@ DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
const viz::internal::Resource* DisplayResourceProvider::LockForRead(
viz::ResourceId id) {
- viz::internal::Resource* resource = GetResource(id);
+ // TODO(ericrk): We should never fail TryGetResource, but we appear to be
+ // doing so on Android in rare cases. Handle this gracefully until a better
+ // solution can be found. https://crbug.com/811858
+ viz::internal::Resource* resource = TryGetResource(id);
+ if (!resource)
+ return nullptr;
+
// TODO(xing.xu): remove locked_for_write.
DCHECK(!resource->locked_for_write)
<< "locked for write: " << resource->locked_for_write;
@@ -537,7 +571,7 @@ const viz::internal::Resource* DisplayResourceProvider::LockForRead(
shared_bitmap_manager_) {
std::unique_ptr<viz::SharedBitmap> bitmap =
shared_bitmap_manager_->GetSharedBitmapFromId(
- resource->size, resource->shared_bitmap_id);
+ resource->size, resource->format, resource->shared_bitmap_id);
if (bitmap) {
resource->SetSharedBitmap(bitmap.get());
resource->owned_shared_bitmap = std::move(bitmap);
@@ -557,13 +591,84 @@ const viz::internal::Resource* DisplayResourceProvider::LockForRead(
void DisplayResourceProvider::UnlockForRead(viz::ResourceId id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
ResourceMap::iterator it = resources_.find(id);
- CHECK(it != resources_.end());
+ // TODO(ericrk): We should never fail to find id, but we appear to be
+ // doing so on Android in rare cases. Handle this gracefully until a better
+ // solution can be found. https://crbug.com/811858
+ if (it == resources_.end())
+ return;
viz::internal::Resource* resource = &it->second;
DCHECK_GT(resource->lock_for_read_count, 0);
DCHECK_EQ(resource->exported_count, 0);
resource->lock_for_read_count--;
- if (resource->marked_for_deletion && !resource->lock_for_read_count) {
+ TryReleaseResource(it);
+}
+
+viz::ResourceMetadata DisplayResourceProvider::LockForExternalUse(
+ viz::ResourceId id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ ResourceMap::iterator it = resources_.find(id);
+ DCHECK(it != resources_.end());
+
+ viz::internal::Resource* resource = &it->second;
+ viz::ResourceMetadata metadata;
+ // TODO(xing.xu): remove locked_for_write.
+ DCHECK(!resource->locked_for_write)
+ << "locked for write: " << resource->locked_for_write;
+ DCHECK_EQ(resource->exported_count, 0);
+ // Uninitialized! Call SetPixels or LockForWrite first.
+ DCHECK(resource->allocated);
+ // Make sure there is no outstanding LockForExternalUse without calling
+ // UnlockForExternalUse.
+ DCHECK(!resource->locked_for_external_use);
+ // TODO(penghuang): support software resource.
+ DCHECK(resource->is_gpu_resource_type());
+
+ metadata.mailbox = resource->mailbox;
+ metadata.backend_format = GrBackendFormat::MakeGL(
+ TextureStorageFormat(resource->format), resource->target);
+ metadata.size = resource->size;
+ metadata.mip_mapped = GrMipMapped::kNo;
+ metadata.origin = kTopLeft_GrSurfaceOrigin;
+ metadata.color_type = ResourceFormatToClosestSkColorType(resource->format);
+ metadata.alpha_type = kPremul_SkAlphaType;
+ metadata.color_space = nullptr;
+ metadata.sync_token = resource->sync_token();
+
+ resource->locked_for_external_use = true;
+ return metadata;
+}
+
+void DisplayResourceProvider::UnlockForExternalUse(
+ viz::ResourceId id,
+ const gpu::SyncToken& sync_token) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ ResourceMap::iterator it = resources_.find(id);
+ DCHECK(it != resources_.end());
+ DCHECK(sync_token.verified_flush());
+
+ viz::internal::Resource* resource = &it->second;
+ DCHECK(resource->locked_for_external_use);
+ // TODO(penghuang): support software resource.
+ DCHECK(resource->is_gpu_resource_type());
+
+ // Update the resource sync token to |sync_token|. When the next frame is
+ // being composited, the DeclareUsedResourcesFromChild() will be called with
+ // resources belong to every child for the next frame. If the resource is not
+ // used by the next frame, the resource will be returned to a child which
+ // owns it with the |sync_token|. The child is responsible for issuing a
+ // WaitSyncToken GL command with the |sync_token| before reusing it.
+ resource->UpdateSyncToken(sync_token);
+ resource->locked_for_external_use = false;
+
+ TryReleaseResource(it);
+}
+
+void DisplayResourceProvider::TryReleaseResource(ResourceMap::iterator it) {
+ viz::ResourceId id = it->first;
+ viz::internal::Resource* resource = &it->second;
+ if (resource->marked_for_deletion && !resource->lock_for_read_count &&
+ !resource->locked_for_external_use) {
if (!resource->child_id) {
// The resource belongs to this ResourceProvider, so it can be destroyed.
#if defined(OS_ANDROID)
@@ -617,6 +722,7 @@ DisplayResourceProvider::ScopedReadLockSkImage::ScopedReadLockSkImage(
: resource_provider_(resource_provider), resource_id_(resource_id) {
const viz::internal::Resource* resource =
resource_provider->LockForRead(resource_id);
+ DCHECK(resource);
if (resource_provider_->resource_sk_image_.find(resource_id) !=
resource_provider_->resource_sk_image_.end()) {
// Use cached sk_image.
@@ -661,6 +767,7 @@ DisplayResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
: resource_provider_(resource_provider), resource_id_(resource_id) {
const viz::internal::Resource* resource =
resource_provider->LockForRead(resource_id);
+ DCHECK(resource);
resource_provider->PopulateSkBitmapWithResource(&sk_bitmap_, resource);
}
@@ -668,6 +775,30 @@ DisplayResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
resource_provider_->UnlockForRead(resource_id_);
}
+DisplayResourceProvider::LockSetForExternalUse::LockSetForExternalUse(
+ DisplayResourceProvider* resource_provider)
+ : resource_provider_(resource_provider) {}
+
+DisplayResourceProvider::LockSetForExternalUse::~LockSetForExternalUse() {
+ DCHECK(resources_.empty());
+}
+
+viz::ResourceMetadata
+DisplayResourceProvider::LockSetForExternalUse::LockResource(
+ viz::ResourceId id) {
+ DCHECK(std::find(resources_.begin(), resources_.end(), id) ==
+ resources_.end());
+ resources_.push_back(id);
+ return resource_provider_->LockForExternalUse(id);
+}
+
+void DisplayResourceProvider::LockSetForExternalUse::UnlockResources(
+ const gpu::SyncToken& sync_token) {
+ for (const auto& id : resources_)
+ resource_provider_->UnlockForExternalUse(id, sync_token);
+ resources_.clear();
+}
+
DisplayResourceProvider::SynchronousFence::SynchronousFence(
gpu::gles2::GLES2Interface* gl)
: gl_(gl), has_synchronized_(true) {}
diff --git a/chromium/cc/resources/display_resource_provider.h b/chromium/cc/resources/display_resource_provider.h
index 7f09f5299d8..5c6baef797e 100644
--- a/chromium/cc/resources/display_resource_provider.h
+++ b/chromium/cc/resources/display_resource_provider.h
@@ -9,6 +9,7 @@
#include "cc/output/overlay_candidate.h"
#include "cc/resources/resource_provider.h"
#include "components/viz/common/resources/resource_fence.h"
+#include "components/viz/common/resources/resource_metadata.h"
namespace viz {
class SharedBitmapManager;
@@ -74,8 +75,8 @@ class CC_EXPORT DisplayResourceProvider : public ResourceProvider {
DisplayResourceProvider* const resource_provider_;
const viz::ResourceId resource_id_;
- GLuint texture_id_;
- GLenum target_;
+ GLuint texture_id_ = 0;
+ GLenum target_ = GL_TEXTURE_2D;
gfx::Size size_;
gfx::ColorSpace color_space_;
@@ -146,6 +147,27 @@ class CC_EXPORT DisplayResourceProvider : public ResourceProvider {
DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSoftware);
};
+ // Maintains set of lock for external use.
+ class CC_EXPORT LockSetForExternalUse {
+ public:
+ explicit LockSetForExternalUse(DisplayResourceProvider* resource_provider);
+ ~LockSetForExternalUse();
+
+ // Lock a resource for external use.
+ viz::ResourceMetadata LockResource(viz::ResourceId resource_id);
+
+ // Unlock all locked resources with a |sync_token|.
+ // See UnlockForExternalUse for the detail. All resources must be unlocked
+ // before destroying this class.
+ void UnlockResources(const gpu::SyncToken& sync_token);
+
+ private:
+ DisplayResourceProvider* const resource_provider_;
+ std::vector<viz::ResourceId> resources_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockSetForExternalUse);
+ };
+
// All resources that are returned to children while an instance of this
// class exists will be stored and returned when the instance is destroyed.
class CC_EXPORT ScopedBatchReturnResources {
@@ -224,10 +246,20 @@ class CC_EXPORT DisplayResourceProvider : public ResourceProvider {
const viz::ResourceIdSet& resources_from_child);
private:
- friend class ScopedBatchReturnResources;
-
const viz::internal::Resource* LockForRead(viz::ResourceId id);
void UnlockForRead(viz::ResourceId id);
+
+ // Lock a resource for external use.
+ viz::ResourceMetadata LockForExternalUse(viz::ResourceId id);
+
+ // Unlock a resource which locked by LockForExternalUse.
+ // The |sync_token| should be waited on before reusing the resouce's backing
+ // to ensure that any external use of it is completed. This |sync_token|
+ // should have been verified.
+ void UnlockForExternalUse(viz::ResourceId id,
+ const gpu::SyncToken& sync_token);
+
+ void TryReleaseResource(ResourceMap::iterator it);
// Binds the given GL resource to a texture target for sampling using the
// specified filter for both minification and magnification. Returns the
// texture target used. The resource must be locked for reading.
diff --git a/chromium/cc/resources/display_resource_provider_unittest.cc b/chromium/cc/resources/display_resource_provider_unittest.cc
new file mode 100644
index 00000000000..b8e3e5647bd
--- /dev/null
+++ b/chromium/cc/resources/display_resource_provider_unittest.cc
@@ -0,0 +1,548 @@
+// 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/resources/display_resource_provider.h"
+#include "cc/resources/layer_tree_resource_provider.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "cc/test/render_pass_test_utils.h"
+#include "cc/test/resource_provider_test_utils.h"
+#include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/common/resources/returned_resource.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/single_release_callback.h"
+#include "components/viz/test/test_context_provider.h"
+#include "components/viz/test/test_gpu_memory_buffer_manager.h"
+#include "components/viz/test/test_shared_bitmap_manager.h"
+#include "components/viz/test/test_texture.h"
+#include "components/viz/test/test_web_graphics_context_3d.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace cc {
+namespace {
+
+static const bool kUseGpuMemoryBufferResources = false;
+
+MATCHER_P(MatchesSyncToken, sync_token, "") {
+ gpu::SyncToken other;
+ memcpy(&other, arg, sizeof(other));
+ return other == sync_token;
+}
+
+static void ReleaseSharedBitmapCallback(
+ std::unique_ptr<viz::SharedBitmap> shared_bitmap,
+ bool* release_called,
+ gpu::SyncToken* release_sync_token,
+ bool* lost_resource_result,
+ const gpu::SyncToken& sync_token,
+ bool lost_resource) {
+ *release_called = true;
+ *release_sync_token = sync_token;
+ *lost_resource_result = lost_resource;
+}
+
+static std::unique_ptr<viz::SharedBitmap> CreateAndFillSharedBitmap(
+ viz::SharedBitmapManager* manager,
+ const gfx::Size& size,
+ viz::ResourceFormat format,
+ uint32_t value) {
+ std::unique_ptr<viz::SharedBitmap> shared_bitmap =
+ manager->AllocateSharedBitmap(size, format);
+ CHECK(shared_bitmap);
+ uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_bitmap->pixels());
+ CHECK(pixels);
+ std::fill_n(pixels, size.GetArea(), value);
+ return shared_bitmap;
+}
+
+static viz::ResourceSettings CreateResourceSettings() {
+ viz::ResourceSettings resource_settings;
+ resource_settings.use_gpu_memory_buffer_resources =
+ kUseGpuMemoryBufferResources;
+ return resource_settings;
+}
+
+// Shared data between multiple ResourceProviderContext. This contains mailbox
+// contents as well as information about sync points.
+class ContextSharedData {
+ public:
+ static std::unique_ptr<ContextSharedData> Create() {
+ return base::WrapUnique(new ContextSharedData());
+ }
+
+ uint32_t InsertFenceSync() { return next_fence_sync_++; }
+
+ void GenMailbox(GLbyte* mailbox) {
+ memset(mailbox, 0, GL_MAILBOX_SIZE_CHROMIUM);
+ memcpy(mailbox, &next_mailbox_, sizeof(next_mailbox_));
+ ++next_mailbox_;
+ }
+
+ void ProduceTexture(const GLbyte* mailbox_name,
+ const gpu::SyncToken& sync_token,
+ scoped_refptr<viz::TestTexture> texture) {
+ uint32_t sync_point = static_cast<uint32_t>(sync_token.release_count());
+
+ unsigned mailbox = 0;
+ memcpy(&mailbox, mailbox_name, sizeof(mailbox));
+ ASSERT_TRUE(mailbox && mailbox < next_mailbox_);
+ textures_[mailbox] = texture;
+ ASSERT_LT(sync_point_for_mailbox_[mailbox], sync_point);
+ sync_point_for_mailbox_[mailbox] = sync_point;
+ }
+
+ scoped_refptr<viz::TestTexture> ConsumeTexture(
+ const GLbyte* mailbox_name,
+ const gpu::SyncToken& sync_token) {
+ unsigned mailbox = 0;
+ memcpy(&mailbox, mailbox_name, sizeof(mailbox));
+ DCHECK(mailbox && mailbox < next_mailbox_);
+
+ // If the latest sync point the context has waited on is before the sync
+ // point for when the mailbox was set, pretend we never saw that
+ // ProduceTexture.
+ if (sync_point_for_mailbox_[mailbox] > sync_token.release_count()) {
+ NOTREACHED();
+ return scoped_refptr<viz::TestTexture>();
+ }
+ return textures_[mailbox];
+ }
+
+ private:
+ ContextSharedData() : next_fence_sync_(1), next_mailbox_(1) {}
+
+ uint64_t next_fence_sync_;
+ unsigned next_mailbox_;
+ using TextureMap =
+ std::unordered_map<unsigned, scoped_refptr<viz::TestTexture>>;
+ TextureMap textures_;
+ std::unordered_map<unsigned, uint32_t> sync_point_for_mailbox_;
+};
+
+class ResourceProviderContext : public viz::TestWebGraphicsContext3D {
+ public:
+ static std::unique_ptr<ResourceProviderContext> Create(
+ ContextSharedData* shared_data) {
+ return base::WrapUnique(new ResourceProviderContext(shared_data));
+ }
+
+ void genSyncToken(GLbyte* sync_token) override {
+ uint64_t fence_sync = shared_data_->InsertFenceSync();
+ gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x123),
+ fence_sync);
+ sync_token_data.SetVerifyFlush();
+ // Commit the ProduceTextureDirectCHROMIUM calls at this point, so that
+ // they're associated with the sync point.
+ for (const std::unique_ptr<PendingProduceTexture>& pending_texture :
+ pending_produce_textures_) {
+ shared_data_->ProduceTexture(pending_texture->mailbox, sync_token_data,
+ pending_texture->texture);
+ }
+ pending_produce_textures_.clear();
+ memcpy(sync_token, &sync_token_data, sizeof(sync_token_data));
+ }
+
+ void waitSyncToken(const GLbyte* sync_token) override {
+ gpu::SyncToken sync_token_data;
+ if (sync_token)
+ memcpy(&sync_token_data, sync_token, sizeof(sync_token_data));
+
+ if (sync_token_data.release_count() >
+ last_waited_sync_token_.release_count()) {
+ last_waited_sync_token_ = sync_token_data;
+ }
+ }
+
+ const gpu::SyncToken& last_waited_sync_token() const {
+ return last_waited_sync_token_;
+ }
+
+ void texStorage2DEXT(GLenum target,
+ GLint levels,
+ GLuint internalformat,
+ GLint width,
+ GLint height) override {
+ CheckTextureIsBound(target);
+ ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
+ ASSERT_EQ(1, levels);
+ GLenum format = GL_RGBA;
+ switch (internalformat) {
+ case GL_RGBA8_OES:
+ break;
+ case GL_BGRA8_EXT:
+ format = GL_BGRA_EXT;
+ break;
+ default:
+ NOTREACHED();
+ }
+ AllocateTexture(gfx::Size(width, height), format);
+ }
+
+ void texImage2D(GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ const void* pixels) override {
+ CheckTextureIsBound(target);
+ ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
+ ASSERT_FALSE(level);
+ ASSERT_EQ(internalformat, format);
+ ASSERT_FALSE(border);
+ ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+ AllocateTexture(gfx::Size(width, height), format);
+ if (pixels)
+ SetPixels(0, 0, width, height, pixels);
+ }
+
+ void texSubImage2D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void* pixels) override {
+ CheckTextureIsBound(target);
+ ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
+ ASSERT_FALSE(level);
+ ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+ {
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ ASSERT_EQ(GLDataFormat(BoundTexture(target)->format), format);
+ }
+ ASSERT_TRUE(pixels);
+ SetPixels(xoffset, yoffset, width, height, pixels);
+ }
+
+ void genMailboxCHROMIUM(GLbyte* mailbox) override {
+ return shared_data_->GenMailbox(mailbox);
+ }
+
+ void produceTextureDirectCHROMIUM(GLuint texture,
+ const GLbyte* mailbox) override {
+ // Delay moving the texture into the mailbox until the next
+ // sync token, so that it is not visible to other contexts that
+ // haven't waited on that sync point.
+ std::unique_ptr<PendingProduceTexture> pending(new PendingProduceTexture);
+ memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox));
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ pending->texture = UnboundTexture(texture);
+ pending_produce_textures_.push_back(std::move(pending));
+ }
+
+ GLuint createAndConsumeTextureCHROMIUM(const GLbyte* mailbox) override {
+ GLuint texture_id = createTexture();
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ scoped_refptr<viz::TestTexture> texture =
+ shared_data_->ConsumeTexture(mailbox, last_waited_sync_token_);
+ namespace_->textures.Replace(texture_id, texture);
+ return texture_id;
+ }
+
+ void GetPixels(const gfx::Size& size,
+ viz::ResourceFormat format,
+ uint8_t* pixels) {
+ CheckTextureIsBound(GL_TEXTURE_2D);
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ scoped_refptr<viz::TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
+ ASSERT_EQ(texture->size, size);
+ ASSERT_EQ(texture->format, format);
+ memcpy(pixels, texture->data.get(), TextureSizeBytes(size, format));
+ }
+
+ protected:
+ explicit ResourceProviderContext(ContextSharedData* shared_data)
+ : shared_data_(shared_data) {}
+
+ private:
+ void AllocateTexture(const gfx::Size& size, GLenum format) {
+ CheckTextureIsBound(GL_TEXTURE_2D);
+ viz::ResourceFormat texture_format = viz::RGBA_8888;
+ switch (format) {
+ case GL_RGBA:
+ texture_format = viz::RGBA_8888;
+ break;
+ case GL_BGRA_EXT:
+ texture_format = viz::BGRA_8888;
+ break;
+ }
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ BoundTexture(GL_TEXTURE_2D)->Reallocate(size, texture_format);
+ }
+
+ void SetPixels(int xoffset,
+ int yoffset,
+ int width,
+ int height,
+ const void* pixels) {
+ CheckTextureIsBound(GL_TEXTURE_2D);
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ scoped_refptr<viz::TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
+ ASSERT_TRUE(texture->data.get());
+ ASSERT_TRUE(xoffset >= 0 && xoffset + width <= texture->size.width());
+ ASSERT_TRUE(yoffset >= 0 && yoffset + height <= texture->size.height());
+ ASSERT_TRUE(pixels);
+ size_t in_pitch = TextureSizeBytes(gfx::Size(width, 1), texture->format);
+ size_t out_pitch =
+ TextureSizeBytes(gfx::Size(texture->size.width(), 1), texture->format);
+ uint8_t* dest = texture->data.get() + yoffset * out_pitch +
+ TextureSizeBytes(gfx::Size(xoffset, 1), texture->format);
+ const uint8_t* src = static_cast<const uint8_t*>(pixels);
+ for (int i = 0; i < height; ++i) {
+ memcpy(dest, src, in_pitch);
+ dest += out_pitch;
+ src += in_pitch;
+ }
+ }
+
+ struct PendingProduceTexture {
+ GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
+ scoped_refptr<viz::TestTexture> texture;
+ };
+ ContextSharedData* shared_data_;
+ gpu::SyncToken last_waited_sync_token_;
+ std::vector<std::unique_ptr<PendingProduceTexture>> pending_produce_textures_;
+};
+
+class DisplayResourceProviderTest : public testing::TestWithParam<bool> {
+ public:
+ explicit DisplayResourceProviderTest(bool child_needs_sync_token)
+ : use_gpu_(GetParam()),
+ child_needs_sync_token_(child_needs_sync_token),
+ shared_data_(ContextSharedData::Create()) {
+ if (use_gpu_) {
+ auto context3d(ResourceProviderContext::Create(shared_data_.get()));
+ context3d_ = context3d.get();
+ context_provider_ =
+ viz::TestContextProvider::Create(std::move(context3d));
+ context_provider_->UnboundTestContext3d()
+ ->set_support_texture_format_bgra8888(true);
+ context_provider_->BindToCurrentThread();
+
+ auto child_context_owned =
+ ResourceProviderContext::Create(shared_data_.get());
+ child_context_ = child_context_owned.get();
+ child_context_provider_ =
+ viz::TestContextProvider::Create(std::move(child_context_owned));
+ child_context_provider_->UnboundTestContext3d()
+ ->set_support_texture_format_bgra8888(true);
+ child_context_provider_->BindToCurrentThread();
+ gpu_memory_buffer_manager_ =
+ std::make_unique<viz::TestGpuMemoryBufferManager>();
+ child_gpu_memory_buffer_manager_ =
+ gpu_memory_buffer_manager_->CreateClientGpuMemoryBufferManager();
+ } else {
+ shared_bitmap_manager_ = std::make_unique<viz::TestSharedBitmapManager>();
+ }
+
+ resource_provider_ = std::make_unique<DisplayResourceProvider>(
+ context_provider_.get(), shared_bitmap_manager_.get());
+
+ MakeChildResourceProvider();
+ }
+
+ DisplayResourceProviderTest() : DisplayResourceProviderTest(true) {}
+
+ bool use_gpu() const { return use_gpu_; }
+
+ void MakeChildResourceProvider() {
+ child_resource_provider_ = std::make_unique<LayerTreeResourceProvider>(
+ child_context_provider_.get(), shared_bitmap_manager_.get(),
+ child_gpu_memory_buffer_manager_.get(), child_needs_sync_token_,
+ CreateResourceSettings());
+ }
+
+ static void CollectResources(
+ std::vector<viz::ReturnedResource>* array,
+ const std::vector<viz::ReturnedResource>& returned) {
+ array->insert(array->end(), returned.begin(), returned.end());
+ }
+
+ static ReturnCallback GetReturnCallback(
+ std::vector<viz::ReturnedResource>* array) {
+ return base::BindRepeating(&DisplayResourceProviderTest::CollectResources,
+ array);
+ }
+
+ static void SetResourceFilter(DisplayResourceProvider* resource_provider,
+ viz::ResourceId id,
+ GLenum filter) {
+ DisplayResourceProvider::ScopedSamplerGL sampler(resource_provider, id,
+ GL_TEXTURE_2D, filter);
+ }
+
+ ResourceProviderContext* context() { return context3d_; }
+
+ viz::ResourceId CreateChildMailbox(gpu::SyncToken* release_sync_token,
+ bool* lost_resource,
+ bool* release_called,
+ gpu::SyncToken* sync_token,
+ viz::ResourceFormat format) {
+ if (use_gpu()) {
+ unsigned texture = child_context_->createTexture();
+ gpu::Mailbox gpu_mailbox;
+ child_context_->genMailboxCHROMIUM(gpu_mailbox.name);
+ child_context_->produceTextureDirectCHROMIUM(texture, gpu_mailbox.name);
+ child_context_->genSyncToken(sync_token->GetData());
+ EXPECT_TRUE(sync_token->HasData());
+
+ std::unique_ptr<viz::SharedBitmap> shared_bitmap;
+ std::unique_ptr<viz::SingleReleaseCallback> callback =
+ viz::SingleReleaseCallback::Create(base::BindRepeating(
+ ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
+ release_called, release_sync_token, lost_resource));
+ viz::TransferableResource gl_resource = viz::TransferableResource::MakeGL(
+ gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, *sync_token);
+ gl_resource.format = format;
+ return child_resource_provider_->ImportResource(gl_resource,
+ std::move(callback));
+ } else {
+ gfx::Size size(64, 64);
+ std::unique_ptr<viz::SharedBitmap> shared_bitmap(
+ CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, format,
+ 0));
+
+ viz::SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
+ std::unique_ptr<viz::SingleReleaseCallback> callback =
+ viz::SingleReleaseCallback::Create(base::BindRepeating(
+ ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
+ release_called, release_sync_token, lost_resource));
+ return child_resource_provider_->ImportResource(
+ viz::TransferableResource::MakeSoftware(
+ shared_bitmap_ptr->id(), shared_bitmap_ptr->sequence_number(),
+ size, format),
+ std::move(callback));
+ }
+ }
+
+ viz::ResourceId MakeGpuResourceAndSendToDisplay(
+ char c,
+ GLuint filter,
+ GLuint target,
+ const gpu::SyncToken& sync_token,
+ DisplayResourceProvider* resource_provider) {
+ ReturnCallback return_callback = base::DoNothing();
+
+ int child = resource_provider->CreateChild(return_callback);
+
+ gpu::Mailbox gpu_mailbox;
+ gpu_mailbox.name[0] = c;
+ gpu_mailbox.name[1] = 0;
+ auto resource = viz::TransferableResource::MakeGL(gpu_mailbox, GL_LINEAR,
+ target, sync_token);
+ resource.id = 11;
+ resource_provider->ReceiveFromChild(child, {resource});
+ auto& map = resource_provider->GetChildToParentMap(child);
+ return map.find(resource.id)->second;
+ }
+
+ protected:
+ const bool use_gpu_;
+ const bool child_needs_sync_token_;
+ const std::unique_ptr<ContextSharedData> shared_data_;
+ ResourceProviderContext* context3d_ = nullptr;
+ ResourceProviderContext* child_context_ = nullptr;
+ scoped_refptr<viz::TestContextProvider> context_provider_;
+ scoped_refptr<viz::TestContextProvider> child_context_provider_;
+ std::unique_ptr<viz::TestGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<viz::TestGpuMemoryBufferManager>
+ child_gpu_memory_buffer_manager_;
+ std::unique_ptr<LayerTreeResourceProvider> child_resource_provider_;
+ std::unique_ptr<viz::TestSharedBitmapManager> shared_bitmap_manager_;
+};
+
+INSTANTIATE_TEST_CASE_P(DisplayResourceProviderTests,
+ DisplayResourceProviderTest,
+ ::testing::Values(false, true));
+
+TEST_P(DisplayResourceProviderTest, LockForExternalUse) {
+ // TODO(penghuang): consider supporting SW mode.
+ if (!use_gpu())
+ return;
+
+ gfx::Size size(1, 1);
+ viz::ResourceFormat format = viz::RGBA_8888;
+
+ viz::ResourceId id1 = child_resource_provider_->CreateGpuTextureResource(
+ size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
+ uint8_t data1[4] = {1, 2, 3, 4};
+ child_resource_provider_->CopyToResource(id1, data1, size);
+ std::vector<viz::ReturnedResource> returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+
+ // Transfer some resources to the parent.
+ ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ resource_ids_to_transfer.push_back(id1);
+
+ std::vector<viz::TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+ &list);
+ ASSERT_EQ(1u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ ResourceProvider::ResourceIdMap resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+
+ unsigned parent_id = resource_map[list.front().id];
+
+ DisplayResourceProvider::LockSetForExternalUse lock_set(
+ resource_provider_.get());
+
+ viz::ResourceMetadata metadata = lock_set.LockResource(parent_id);
+ ASSERT_EQ(size, metadata.size);
+ ASSERT_FALSE(metadata.mailbox.IsZero());
+ ASSERT_TRUE(metadata.sync_token.HasData());
+
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ viz::ResourceIdSet());
+ // The resource should not be returned due to the external use lock.
+ EXPECT_EQ(0u, returned_to_child.size());
+
+ gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x234),
+ 0x456);
+ sync_token.SetVerifyFlush();
+ lock_set.UnlockResources(sync_token);
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ viz::ResourceIdSet());
+ // The resource should be returned after the lock is released.
+ EXPECT_EQ(1u, returned_to_child.size());
+ EXPECT_EQ(sync_token, returned_to_child[0].sync_token);
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+ child_resource_provider_->DeleteResource(id1);
+ EXPECT_EQ(0u, child_resource_provider_->num_resources());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/resources/layer_tree_resource_provider.cc b/chromium/cc/resources/layer_tree_resource_provider.cc
index 38f17c03d25..44720a3ffcb 100644
--- a/chromium/cc/resources/layer_tree_resource_provider.cc
+++ b/chromium/cc/resources/layer_tree_resource_provider.cc
@@ -7,10 +7,10 @@
#include "base/bits.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
-#include "cc/resources/resource_util.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"
+#include "components/viz/common/resources/resource_sizes.h"
#include "components/viz/common/resources/shared_bitmap_manager.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
@@ -403,23 +403,25 @@ viz::ResourceId LayerTreeResourceProvider::CreateGpuMemoryBufferResource(
viz::ResourceId LayerTreeResourceProvider::CreateBitmapResource(
const gfx::Size& size,
- const gfx::ColorSpace& color_space) {
+ const gfx::ColorSpace& color_space,
+ viz::ResourceFormat format) {
DCHECK(!compositor_context_provider_);
DCHECK(!size.IsEmpty());
+ DCHECK(viz::IsBitmapFormatSupported(format));
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// TODO(danakj): Allocate this outside ResourceProvider.
std::unique_ptr<viz::SharedBitmap> bitmap =
- shared_bitmap_manager_->AllocateSharedBitmap(size);
+ shared_bitmap_manager_->AllocateSharedBitmap(size, format);
DCHECK(bitmap);
DCHECK(bitmap->pixels());
viz::ResourceId id = next_id_++;
viz::internal::Resource* resource = InsertResource(
- id, viz::internal::Resource(size, viz::internal::Resource::INTERNAL,
- viz::ResourceTextureHint::kDefault,
- viz::ResourceType::kBitmap, viz::RGBA_8888,
- color_space));
+ id,
+ viz::internal::Resource(size, viz::internal::Resource::INTERNAL,
+ viz::ResourceTextureHint::kDefault,
+ viz::ResourceType::kBitmap, format, color_space));
resource->SetSharedBitmap(bitmap.get());
resource->owned_shared_bitmap = std::move(bitmap);
return id;
@@ -502,7 +504,7 @@ void LayerTreeResourceProvider::CopyToResource(viz::ResourceId id,
if (resource->format == viz::ETC1) {
DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
int image_bytes =
- ResourceUtil::CheckedSizeInBytes<int>(image_size, viz::ETC1);
+ viz::ResourceSizes::CheckedSizeInBytes<int>(image_size, viz::ETC1);
gl->CompressedTexImage2D(resource->target, 0, GLInternalFormat(viz::ETC1),
image_size.width(), image_size.height(), 0,
image_bytes, image);
@@ -790,6 +792,7 @@ LayerTreeResourceProvider::ScopedWriteLockGpu::ScopedWriteLockGpu(
DCHECK_EQ(resource->type, viz::ResourceType::kTexture);
resource_provider->CreateTexture(resource);
size_ = resource->size;
+ usage_ = resource->usage;
format_ = resource->format;
color_space_ = resource_provider_->GetResourceColorSpaceForRaster(resource);
texture_id_ = resource->gl_id;
@@ -892,7 +895,8 @@ GLuint LayerTreeResourceProvider::ScopedWriteLockRaster::ConsumeTexture(
DCHECK(ri);
DCHECK(!mailbox_.IsZero());
- GLuint texture_id = ri->CreateAndConsumeTextureCHROMIUM(mailbox_.name);
+ GLuint texture_id =
+ ri->CreateAndConsumeTexture(is_overlay_, usage_, format_, mailbox_.name);
DCHECK(texture_id);
LazyAllocate(ri, texture_id);
@@ -911,13 +915,10 @@ void LayerTreeResourceProvider::ScopedWriteLockRaster::LazyAllocate(
return;
allocated_ = true;
- ri->BindTexture(target_, texture_id);
- ri->TexStorageForRaster(
- target_, format_, size_.width(), size_.height(),
- is_overlay_ ? gpu::raster::kOverlay : gpu::raster::kNone);
+ ri->TexStorage2D(texture_id, 1, size_.width(), size_.height());
if (is_overlay_ && color_space_.IsValid()) {
- ri->SetColorSpaceMetadataCHROMIUM(
- texture_id, reinterpret_cast<GLColorSpace>(&color_space_));
+ ri->SetColorSpaceMetadata(texture_id,
+ reinterpret_cast<GLColorSpace>(&color_space_));
}
}
@@ -987,7 +988,6 @@ LayerTreeResourceProvider::ScopedSkSurface::ScopedSkSurface(
GLenum texture_target,
const gfx::Size& size,
viz::ResourceFormat format,
- bool use_distance_field_text,
bool can_use_lcd_text,
int msaa_sample_count) {
GrGLTextureInfo texture_info;
@@ -996,15 +996,7 @@ LayerTreeResourceProvider::ScopedSkSurface::ScopedSkSurface(
texture_info.fFormat = TextureStorageFormat(format);
GrBackendTexture backend_texture(size.width(), size.height(),
GrMipMapped::kNo, texture_info);
- uint32_t flags =
- use_distance_field_text ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 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);
- }
+ SkSurfaceProps surface_props = ComputeSurfaceProps(can_use_lcd_text);
surface_ = SkSurface::MakeFromBackendTextureAsRenderTarget(
gr_context, backend_texture, kTopLeft_GrSurfaceOrigin, msaa_sample_count,
ResourceFormatToClosestSkColorType(format), nullptr, &surface_props);
@@ -1015,6 +1007,19 @@ LayerTreeResourceProvider::ScopedSkSurface::~ScopedSkSurface() {
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);
diff --git a/chromium/cc/resources/layer_tree_resource_provider.h b/chromium/cc/resources/layer_tree_resource_provider.h
index 92ae354a77f..07a85f50a70 100644
--- a/chromium/cc/resources/layer_tree_resource_provider.h
+++ b/chromium/cc/resources/layer_tree_resource_provider.h
@@ -71,7 +71,8 @@ class CC_EXPORT LayerTreeResourceProvider : public ResourceProvider {
gfx::BufferUsage usage,
const gfx::ColorSpace& color_space);
viz::ResourceId CreateBitmapResource(const gfx::Size& size,
- const gfx::ColorSpace& color_space);
+ const gfx::ColorSpace& color_space,
+ viz::ResourceFormat format);
void DeleteResource(viz::ResourceId id);
@@ -185,6 +186,7 @@ class CC_EXPORT LayerTreeResourceProvider : public ResourceProvider {
// The following are copied from the resource.
gfx::Size size_;
+ gfx::BufferUsage usage_;
viz::ResourceFormat format_;
gfx::ColorSpace color_space_;
GLuint texture_id_;
@@ -285,13 +287,14 @@ class CC_EXPORT LayerTreeResourceProvider : public ResourceProvider {
GLenum texture_target,
const gfx::Size& size,
viz::ResourceFormat format,
- bool use_distance_field_text,
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_;
diff --git a/chromium/cc/resources/layer_tree_resource_provider_unittest.cc b/chromium/cc/resources/layer_tree_resource_provider_unittest.cc
index 4069c9b256f..b0a47f2a805 100644
--- a/chromium/cc/resources/layer_tree_resource_provider_unittest.cc
+++ b/chromium/cc/resources/layer_tree_resource_provider_unittest.cc
@@ -358,8 +358,8 @@ TEST_P(LayerTreeResourceProviderTest,
gfx::Size(3, 4), viz::ResourceTextureHint::kDefault, viz::RGBA_8888,
gfx::ColorSpace());
} else {
- norm_id =
- provider().CreateBitmapResource(gfx::Size(3, 4), gfx::ColorSpace());
+ norm_id = provider().CreateBitmapResource(
+ gfx::Size(3, 4), gfx::ColorSpace(), viz::RGBA_8888);
}
provider().AllocateForTesting(norm_id);
diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc
index c12c9550e44..659d5743972 100644
--- a/chromium/cc/resources/resource_pool.cc
+++ b/chromium/cc/resources/resource_pool.cc
@@ -20,7 +20,7 @@
#include "build/build_config.h"
#include "cc/base/container_util.h"
#include "cc/resources/layer_tree_resource_provider.h"
-#include "cc/resources/resource_util.h"
+#include "components/viz/common/resources/resource_sizes.h"
using base::trace_event::MemoryAllocatorDump;
using base::trace_event::MemoryDumpLevelOfDetail;
@@ -124,8 +124,9 @@ ResourcePool::PoolResource* ResourcePool::ReuseResource(
// Transfer resource to |in_use_resources_|.
in_use_resources_[resource->unique_id()] = std::move(*it);
unused_resources_.erase(it);
- in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
- resource->size(), resource->format());
+ in_use_memory_usage_bytes_ +=
+ viz::ResourceSizes::UncheckedSizeInBytes<size_t>(resource->size(),
+ resource->format());
return resource;
}
return nullptr;
@@ -135,19 +136,19 @@ ResourcePool::PoolResource* ResourcePool::CreateResource(
const gfx::Size& size,
viz::ResourceFormat format,
const gfx::ColorSpace& color_space) {
- DCHECK(ResourceUtil::VerifySizeInBytes<size_t>(size, format));
+ DCHECK(viz::ResourceSizes::VerifySizeInBytes<size_t>(size, format));
auto pool_resource = std::make_unique<PoolResource>(
next_resource_unique_id_++, size, format, color_space);
total_memory_usage_bytes_ +=
- ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
+ viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format);
++total_resource_count_;
PoolResource* resource = pool_resource.get();
in_use_resources_[resource->unique_id()] = std::move(pool_resource);
in_use_memory_usage_bytes_ +=
- ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
+ viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format);
return resource;
}
@@ -231,8 +232,9 @@ ResourcePool::TryAcquireResourceForPartialRaster(
in_use_resources_[resource->unique_id()] =
std::move(*iter_resource_to_return);
unused_resources_.erase(iter_resource_to_return);
- in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
- resource->size(), resource->format());
+ in_use_memory_usage_bytes_ +=
+ viz::ResourceSizes::UncheckedSizeInBytes<size_t>(resource->size(),
+ resource->format());
*total_invalidated_rect = resource->invalidated_rect();
// Clear the invalidated rect and content ID on the resource being retunred.
@@ -282,9 +284,9 @@ void ResourcePool::OnResourceReleased(size_t unique_id,
void ResourcePool::PrepareForExport(const InUsePoolResource& resource) {
// Exactly one of gpu or software backing should exist.
DCHECK(resource.resource_->gpu_backing() ||
- resource.resource_->shared_bitmap());
+ resource.resource_->software_backing());
DCHECK(!resource.resource_->gpu_backing() ||
- !resource.resource_->shared_bitmap());
+ !resource.resource_->software_backing());
viz::TransferableResource transferable;
if (resource.resource_->gpu_backing()) {
transferable = viz::TransferableResource::MakeGLOverlay(
@@ -297,9 +299,11 @@ void ResourcePool::PrepareForExport(const InUsePoolResource& resource) {
resource.resource_->gpu_backing()->wait_on_fence_required;
} else {
transferable = viz::TransferableResource::MakeSoftware(
- resource.resource_->shared_bitmap()->id(),
- resource.resource_->shared_bitmap()->sequence_number(),
- resource.resource_->size());
+ resource.resource_->software_backing()->shared_bitmap_id,
+ // Not needed since this software resource's SharedBitmapId was
+ // notified to the display compositor through the CompositorFrameSink.
+ /*sequence_number=*/0, resource.resource_->size(),
+ resource.resource_->format());
}
transferable.format = resource.resource_->format();
transferable.buffer_format = viz::BufferFormat(transferable.format);
@@ -362,8 +366,9 @@ void ResourcePool::ReleaseResource(InUsePoolResource in_use_resource) {
CHECK(it->second.get());
pool_resource->set_last_usage(base::TimeTicks::Now());
- in_use_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
- pool_resource->size(), pool_resource->format());
+ in_use_memory_usage_bytes_ -=
+ viz::ResourceSizes::UncheckedSizeInBytes<size_t>(pool_resource->size(),
+ pool_resource->format());
// Save the ResourceId since the |pool_resource| can be deleted in the next
// step.
@@ -434,7 +439,7 @@ bool ResourcePool::ResourceUsageTooHigh() {
}
void ResourcePool::DeleteResource(std::unique_ptr<PoolResource> resource) {
- size_t resource_bytes = ResourceUtil::UncheckedSizeInBytes<size_t>(
+ size_t resource_bytes = viz::ResourceSizes::UncheckedSizeInBytes<size_t>(
resource->size(), resource->format());
total_memory_usage_bytes_ -= resource_bytes;
--total_resource_count_;
@@ -569,12 +574,11 @@ void ResourcePool::PoolResource::OnMemoryDump(
bool is_free) const {
base::UnguessableToken shm_guid;
base::trace_event::MemoryAllocatorDumpGuid backing_guid;
- if (shared_bitmap_) {
- // Software resources are in shared memory but are kept closed to avoid
- // holding an fd open. So there is no SharedMemoryHandle to get a guid
- // from.
- DCHECK(!shared_bitmap_->GetSharedMemoryHandle().IsValid());
- backing_guid = viz::GetSharedBitmapGUIDForTracing(shared_bitmap_->id());
+ if (software_backing_) {
+ // Software resources are allocated in shared memory for use cross-process
+ // in the display compositor. So we use the guid for the shared memory to
+ // identify them in tracing in all processes.
+ shm_guid = software_backing_->SharedMemoryGuid();
} else if (gpu_backing_) {
// We prefer the SharedMemoryGuid() if it exists, if the resource is backed
// by shared memory.
@@ -610,7 +614,7 @@ void ResourcePool::PoolResource::OnMemoryDump(
}
uint64_t total_bytes =
- ResourceUtil::UncheckedSizeInBytesAligned<size_t>(size_, format_);
+ viz::ResourceSizes::UncheckedSizeInBytesAligned<size_t>(size_, format_);
dump->AddScalar(MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, total_bytes);
diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h
index 659abb85549..b55cf829297 100644
--- a/chromium/cc/resources/resource_pool.h
+++ b/chromium/cc/resources/resource_pool.h
@@ -14,7 +14,6 @@
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/memory_coordinator_client.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
@@ -51,6 +50,15 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
public:
virtual ~GpuBacking() = default;
+ // Guids for for memory dumps. This guid will be valid once the GpuBacking
+ // has memory allocated. Called on the compositor thread.
+ virtual base::trace_event::MemoryAllocatorDumpGuid MemoryDumpGuid(
+ uint64_t tracing_process_id) = 0;
+ // Some gpu resources can be shared memory-backed, and this guid should be
+ // prefered in that case. But if not then this will be empty. Called on the
+ // compositor thread.
+ virtual base::UnguessableToken SharedMemoryGuid() = 0;
+
gpu::Mailbox mailbox;
gpu::SyncToken mailbox_sync_token;
GLenum texture_target = 0;
@@ -61,18 +69,23 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
bool wait_on_fence_required = false;
// Set by the ResourcePool when a resource is returned from the display
- // compositor. The client of ResourcePool needs to wait on this token, if it
- // exists, before using a resource handed out by the ResourcePool.
+ // compositor, or when the resource texture and mailbox are created for the
+ // first time, if the resource is shared with another context. The client of
+ // ResourcePool needs to wait on this token if it exists, before using a
+ // resource handed out by the ResourcePool.
gpu::SyncToken returned_sync_token;
+ };
- // Guids for for memory dumps. This guid will be valid once the GpuBacking
- // has memory allocated. Called on the compositor thread.
- virtual base::trace_event::MemoryAllocatorDumpGuid MemoryDumpGuid(
- uint64_t tracing_process_id) = 0;
- // Some gpu resources can be shared memory-backed, and this guid should be
- // prefered in that case. But if not then this will be empty. Called on the
- // compositor thread.
+ // A base class to hold ownership of software backed PoolResources. Allows the
+ // client to define destruction semantics.
+ class SoftwareBacking {
+ public:
+ virtual ~SoftwareBacking() = default;
+
+ // Return the guid for this resource, based on the shared memory backing it.
virtual base::UnguessableToken SharedMemoryGuid() = 0;
+
+ viz::SharedBitmapId shared_bitmap_id;
};
// Scoped move-only object returned when getting a resource from the pool.
@@ -125,15 +138,13 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
}
// Only valid when the ResourcePool is vending software-backed resources.
- viz::SharedBitmap* shared_bitmap() const {
+ SoftwareBacking* software_backing() const {
DCHECK(!is_gpu_);
- return resource_->shared_bitmap();
+ return resource_->software_backing();
}
- void set_shared_bitmap(
- std::unique_ptr<viz::SharedBitmap> shared_bitmap) const {
+ void set_software_backing(std::unique_ptr<SoftwareBacking> software) const {
DCHECK(!is_gpu_);
- DCHECK(!resource_->shared_bitmap());
- resource_->set_shared_bitmap(std::move(shared_bitmap));
+ resource_->set_software_backing(std::move(software));
}
// Production code should not be built around these ids, but tests use them
@@ -248,9 +259,11 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
gpu_backing_ = std::move(gpu);
}
- viz::SharedBitmap* shared_bitmap() const { return shared_bitmap_.get(); }
- void set_shared_bitmap(std::unique_ptr<viz::SharedBitmap> shared_bitmap) {
- shared_bitmap_ = std::move(shared_bitmap);
+ SoftwareBacking* software_backing() const {
+ return software_backing_.get();
+ }
+ void set_software_backing(std::unique_ptr<SoftwareBacking> software) {
+ software_backing_ = std::move(software);
}
uint64_t content_id() const { return content_id_; }
@@ -297,7 +310,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
// The backing for software resources. Initially null for resources given
// out by ResourcePool, to be filled in by the client. Is destroyed on the
// compositor thread.
- std::unique_ptr<viz::SharedBitmap> shared_bitmap_;
+ std::unique_ptr<SoftwareBacking> software_backing_;
};
// Callback from the ResourceProvider to notify when an exported PoolResource
diff --git a/chromium/cc/resources/resource_pool_unittest.cc b/chromium/cc/resources/resource_pool_unittest.cc
index 0aa7a5ce8d2..cf233dc40b4 100644
--- a/chromium/cc/resources/resource_pool_unittest.cc
+++ b/chromium/cc/resources/resource_pool_unittest.cc
@@ -9,8 +9,8 @@
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "cc/resources/resource_util.h"
#include "cc/test/fake_resource_provider.h"
+#include "components/viz/common/resources/resource_sizes.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"
@@ -82,7 +82,7 @@ TEST_F(ResourcePoolTest, AccountingSingleResource) {
viz::ResourceFormat format = viz::RGBA_8888;
gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
size_t resource_bytes =
- ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
+ viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format);
ResourcePool::InUsePoolResource resource =
resource_pool_->AcquireResource(size, format, color_space);
diff --git a/chromium/cc/resources/resource_provider.cc b/chromium/cc/resources/resource_provider.cc
index e6eb1222e65..fcc3b6158e7 100644
--- a/chromium/cc/resources/resource_provider.cc
+++ b/chromium/cc/resources/resource_provider.cc
@@ -23,8 +23,8 @@
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
-#include "cc/resources/resource_util.h"
#include "components/viz/common/gpu/context_provider.h"
+#include "components/viz/common/resources/resource_sizes.h"
#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "gpu/command_buffer/client/context_support.h"
@@ -149,21 +149,31 @@ viz::internal::Resource* ResourceProvider::InsertResource(
viz::internal::Resource* ResourceProvider::GetResource(viz::ResourceId id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // TODO(ericrk): Changing the DCHECKs in this function to CHECKs to debug
- // https://crbug.com/811858.
- CHECK(id);
+ DCHECK(id);
ResourceMap::iterator it = resources_.find(id);
- CHECK(it != resources_.end());
+ DCHECK(it != resources_.end());
+ return &it->second;
+}
+
+viz::internal::Resource* ResourceProvider::TryGetResource(viz::ResourceId id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!id)
+ return nullptr;
+ ResourceMap::iterator it = resources_.find(id);
+ if (it == resources_.end())
+ return nullptr;
return &it->second;
}
void ResourceProvider::PopulateSkBitmapWithResource(
SkBitmap* sk_bitmap,
const viz::internal::Resource* resource) {
- DCHECK_EQ(viz::RGBA_8888, resource->format);
+ DCHECK(IsBitmapFormatSupported(resource->format));
SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
resource->size.height());
- sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
+ bool pixels_installed =
+ sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
+ DCHECK(pixels_installed);
}
void ResourceProvider::WaitSyncTokenInternal(
@@ -207,7 +217,7 @@ bool ResourceProvider::OnMemoryDump(
backing_memory_allocated = !!resource.gl_id;
break;
case viz::ResourceType::kBitmap:
- backing_memory_allocated = resource.has_shared_bitmap_id;
+ backing_memory_allocated = !!resource.shared_bitmap;
break;
}
@@ -224,11 +234,16 @@ bool ResourceProvider::OnMemoryDump(
base::trace_event::MemoryAllocatorDump* dump =
pmd->CreateAllocatorDump(dump_name);
- uint64_t total_bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
- resource.size, resource.format);
- dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
- base::trace_event::MemoryAllocatorDump::kUnitsBytes,
- static_cast<uint64_t>(total_bytes));
+ // Texture resources may not come with a size, in which case don't report
+ // one.
+ if (!resource.size.IsEmpty()) {
+ uint64_t total_bytes =
+ viz::ResourceSizes::UncheckedSizeInBytesAligned<size_t>(
+ resource.size, resource.format);
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ static_cast<uint64_t>(total_bytes));
+ }
// Resources may be shared across processes and require a shared GUID to
// prevent double counting the memory.
@@ -236,10 +251,16 @@ bool ResourceProvider::OnMemoryDump(
base::UnguessableToken shared_memory_guid;
switch (resource.type) {
case viz::ResourceType::kGpuMemoryBuffer:
- guid =
- resource.gpu_memory_buffer->GetGUIDForTracing(tracing_process_id);
+ // GpuMemoryBuffers may be backed by shared memory, and in that case we
+ // use the guid from there to attribute for the global shared memory
+ // dumps. Otherwise, they may be backed by native structures, and we
+ // fall back to that with GetGUIDForTracing.
shared_memory_guid =
resource.gpu_memory_buffer->GetHandle().handle.GetGUID();
+ if (shared_memory_guid.is_empty()) {
+ guid =
+ resource.gpu_memory_buffer->GetGUIDForTracing(tracing_process_id);
+ }
break;
case viz::ResourceType::kTexture:
DCHECK(resource.gl_id);
@@ -249,24 +270,28 @@ bool ResourceProvider::OnMemoryDump(
resource.gl_id);
break;
case viz::ResourceType::kBitmap:
- DCHECK(resource.has_shared_bitmap_id);
- guid = viz::GetSharedBitmapGUIDForTracing(resource.shared_bitmap_id);
- if (resource.shared_bitmap) {
- shared_memory_guid =
- resource.shared_bitmap->GetSharedMemoryHandle().GetGUID();
- }
+ // If the resource comes from out of process, it will have this id,
+ // which we prefer. Otherwise, we fall back to the SharedBitmapGUID
+ // which can be generated for in-process bitmaps.
+ shared_memory_guid = resource.shared_bitmap->GetCrossProcessGUID();
+ if (shared_memory_guid.is_empty())
+ guid = viz::GetSharedBitmapGUIDForTracing(resource.shared_bitmap_id);
break;
}
- DCHECK(!guid.empty());
+ DCHECK(!shared_memory_guid.is_empty() || !guid.empty());
- const int kImportance = 2;
+ const int kImportanceForInteral = 2;
+ const int kImportanceForExternal = 1;
+ int importance = resource.origin == viz::internal::Resource::INTERNAL
+ ? kImportanceForInteral
+ : kImportanceForExternal;
if (!shared_memory_guid.is_empty()) {
pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), shared_memory_guid,
- kImportance);
+ importance);
} else {
pmd->CreateSharedGlobalAllocatorDump(guid);
- pmd->AddOwnershipEdge(dump->guid(), guid, kImportance);
+ pmd->AddOwnershipEdge(dump->guid(), guid, importance);
}
}
diff --git a/chromium/cc/resources/resource_provider.h b/chromium/cc/resources/resource_provider.h
index fa07aae6595..31e46d23620 100644
--- a/chromium/cc/resources/resource_provider.h
+++ b/chromium/cc/resources/resource_provider.h
@@ -92,6 +92,11 @@ class CC_EXPORT ResourceProvider
viz::internal::Resource resource);
viz::internal::Resource* GetResource(viz::ResourceId id);
+ // TODO(ericrk): TryGetResource is part of a temporary workaround for cases
+ // where resources which should be available are missing. This version may
+ // return nullptr if a resource is not found. https://crbug.com/811858
+ viz::internal::Resource* TryGetResource(viz::ResourceId id);
+
void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap,
const viz::internal::Resource* resource);
diff --git a/chromium/cc/resources/resource_provider_unittest.cc b/chromium/cc/resources/resource_provider_unittest.cc
index 90cef4cadad..b569bcdd8a7 100644
--- a/chromium/cc/resources/resource_provider_unittest.cc
+++ b/chromium/cc/resources/resource_provider_unittest.cc
@@ -81,9 +81,10 @@ static void ReleaseSharedBitmapCallback(
static std::unique_ptr<viz::SharedBitmap> CreateAndFillSharedBitmap(
viz::SharedBitmapManager* manager,
const gfx::Size& size,
+ viz::ResourceFormat format,
uint32_t value) {
std::unique_ptr<viz::SharedBitmap> shared_bitmap =
- manager->AllocateSharedBitmap(size);
+ manager->AllocateSharedBitmap(size, format);
CHECK(shared_bitmap);
uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_bitmap->pixels());
CHECK(pixels);
@@ -469,7 +470,8 @@ class ResourceProviderTest : public testing::TestWithParam<bool> {
viz::ResourceId CreateChildMailbox(gpu::SyncToken* release_sync_token,
bool* lost_resource,
bool* release_called,
- gpu::SyncToken* sync_token) {
+ gpu::SyncToken* sync_token,
+ viz::ResourceFormat format) {
if (use_gpu()) {
unsigned texture = child_context_->createTexture();
gpu::Mailbox gpu_mailbox;
@@ -483,14 +485,16 @@ class ResourceProviderTest : public testing::TestWithParam<bool> {
viz::SingleReleaseCallback::Create(base::Bind(
ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
release_called, release_sync_token, lost_resource));
- return child_resource_provider_->ImportResource(
- viz::TransferableResource::MakeGL(gpu_mailbox, GL_LINEAR,
- GL_TEXTURE_2D, *sync_token),
- std::move(callback));
+ viz::TransferableResource gl_resource = viz::TransferableResource::MakeGL(
+ gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, *sync_token);
+ gl_resource.format = format;
+ return child_resource_provider_->ImportResource(gl_resource,
+ std::move(callback));
} else {
gfx::Size size(64, 64);
std::unique_ptr<viz::SharedBitmap> shared_bitmap(
- CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, 0));
+ CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, format,
+ 0));
viz::SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
std::unique_ptr<viz::SingleReleaseCallback> callback =
@@ -500,7 +504,7 @@ class ResourceProviderTest : public testing::TestWithParam<bool> {
return child_resource_provider_->ImportResource(
viz::TransferableResource::MakeSoftware(
shared_bitmap_ptr->id(), shared_bitmap_ptr->sequence_number(),
- size),
+ size, format),
std::move(callback));
}
}
@@ -552,8 +556,8 @@ TEST_P(ResourceProviderTest, Basic) {
viz::ResourceId id;
if (!use_gpu()) {
- id =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
+ id = child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace(),
+ format);
} else {
id = child_resource_provider_->CreateGpuTextureResource(
size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
@@ -606,10 +610,10 @@ TEST_P(ResourceProviderTest, SimpleUpload) {
size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
} else {
- id1 =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
- id2 =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
+ id1 = child_resource_provider_->CreateBitmapResource(
+ size, gfx::ColorSpace(), format);
+ id2 = child_resource_provider_->CreateBitmapResource(
+ size, gfx::ColorSpace(), format);
}
uint8_t image[16] = {0};
@@ -1415,13 +1419,13 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
size_t pixel_size = TextureSizeBytes(size, format);
ASSERT_EQ(4U, pixel_size);
- viz::ResourceId id1 =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
+ viz::ResourceId id1 = child_resource_provider_->CreateBitmapResource(
+ size, gfx::ColorSpace(), format);
uint8_t data1[4] = { 1, 2, 3, 4 };
child_resource_provider_->CopyToResource(id1, data1, size);
- viz::ResourceId id2 =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
+ viz::ResourceId id2 = child_resource_provider_->CreateBitmapResource(
+ size, gfx::ColorSpace(), format);
uint8_t data2[4] = { 5, 5, 5, 5 };
child_resource_provider_->CopyToResource(id2, data2, size);
@@ -1641,8 +1645,8 @@ TEST_P(ResourceProviderTest, TransferInvalidSoftware) {
size_t pixel_size = TextureSizeBytes(size, format);
ASSERT_EQ(4U, pixel_size);
- viz::ResourceId id1 =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
+ viz::ResourceId id1 = child_resource_provider_->CreateBitmapResource(
+ size, gfx::ColorSpace(), format);
uint8_t data1[4] = { 1, 2, 3, 4 };
child_resource_provider_->CopyToResource(id1, data1, size);
@@ -1697,10 +1701,10 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) {
id2 = child_resource_provider_->CreateGpuTextureResource(
size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
} else {
- id1 =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
- id2 =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
+ id1 = child_resource_provider_->CreateBitmapResource(
+ size, gfx::ColorSpace(), format);
+ id2 = child_resource_provider_->CreateBitmapResource(
+ size, gfx::ColorSpace(), format);
}
uint8_t data1[4] = { 1, 2, 3, 4 };
@@ -1763,10 +1767,10 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
id2 = child_resource_provider_->CreateGpuTextureResource(
size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
} else {
- id1 =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
- id2 =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
+ id1 = child_resource_provider_->CreateBitmapResource(
+ size, gfx::ColorSpace(), format);
+ id2 = child_resource_provider_->CreateBitmapResource(
+ size, gfx::ColorSpace(), format);
}
uint8_t data1[4] = {1, 2, 3, 4};
@@ -1820,8 +1824,8 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) {
id = child_resource_provider_->CreateGpuTextureResource(
size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
} else {
- id =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
+ id = child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace(),
+ format);
}
uint8_t data[4] = { 1, 2, 3, 4 };
@@ -2149,8 +2153,8 @@ TEST_P(ResourceProviderTest, LostResourceInParent) {
id = child_resource_provider_->CreateGpuTextureResource(
size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
} else {
- id =
- child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace());
+ id = child_resource_provider_->CreateBitmapResource(size, gfx::ColorSpace(),
+ format);
}
child_resource_provider_->AllocateForTesting(id);
@@ -2208,8 +2212,9 @@ TEST_P(ResourceProviderTest, LostMailboxInParent) {
bool lost_resource = false;
bool release_called = false;
gpu::SyncToken sync_token;
- viz::ResourceId resource = CreateChildMailbox(
- &release_sync_token, &lost_resource, &release_called, &sync_token);
+ viz::ResourceId resource =
+ CreateChildMailbox(&release_sync_token, &lost_resource, &release_called,
+ &sync_token, viz::RGBA_8888);
std::vector<viz::ReturnedResource> returned_to_child;
int child_id =
@@ -2283,8 +2288,9 @@ TEST_P(ResourceProviderTest, Shutdown) {
bool lost_resource = false;
bool release_called = false;
gpu::SyncToken sync_token;
- viz::ResourceId id = CreateChildMailbox(&release_sync_token, &lost_resource,
- &release_called, &sync_token);
+ viz::ResourceId id =
+ CreateChildMailbox(&release_sync_token, &lost_resource, &release_called,
+ &sync_token, viz::RGBA_8888);
if (i == kShutdownAfterExport || i == kShutdownAfterExportAndReturn ||
i == kShutdownAfterExportAndReturnWithLostResource ||
@@ -2566,9 +2572,10 @@ TEST_P(ResourceProviderTest, ImportedResource_SharedMemory) {
return;
gfx::Size size(64, 64);
+ viz::ResourceFormat format = viz::RGBA_8888;
const uint32_t kBadBeef = 0xbadbeef;
- std::unique_ptr<viz::SharedBitmap> shared_bitmap(
- CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, kBadBeef));
+ std::unique_ptr<viz::SharedBitmap> shared_bitmap(CreateAndFillSharedBitmap(
+ shared_bitmap_manager_.get(), size, format, kBadBeef));
auto resource_provider(std::make_unique<DisplayResourceProvider>(
nullptr, shared_bitmap_manager_.get()));
@@ -2583,7 +2590,7 @@ TEST_P(ResourceProviderTest, ImportedResource_SharedMemory) {
viz::SingleReleaseCallback::Create(
base::Bind(&ReleaseCallback, &release_sync_token, &lost_resource));
auto resource = viz::TransferableResource::MakeSoftware(
- shared_bitmap->id(), shared_bitmap->sequence_number(), size);
+ shared_bitmap->id(), shared_bitmap->sequence_number(), size, format);
viz::ResourceId resource_id =
child_resource_provider->ImportResource(resource, std::move(callback));
diff --git a/chromium/cc/resources/resource_util.h b/chromium/cc/resources/resource_util.h
deleted file mode 100644
index e263aa67e70..00000000000
--- a/chromium/cc/resources/resource_util.h
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2015 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_RESOURCE_UTIL_H_
-#define CC_RESOURCES_RESOURCE_UTIL_H_
-
-#include <stddef.h>
-
-#include <limits>
-
-#include "base/macros.h"
-#include "base/numerics/safe_math.h"
-#include "cc/base/math_util.h"
-#include "cc/cc_export.h"
-#include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_format_utils.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace cc {
-
-class CC_EXPORT ResourceUtil {
- public:
- // Returns true if the width is valid and fits in bytes, false otherwise.
- template <typename T>
- static bool VerifyWidthInBytes(int width, viz::ResourceFormat format);
- // Returns true if the size is valid and fits in bytes, false otherwise.
- template <typename T>
- static bool VerifySizeInBytes(const gfx::Size& size,
- viz::ResourceFormat format);
-
- // Dies with a CRASH() if the width can not be represented as a positive
- // number of bytes.
- template <typename T>
- static T CheckedWidthInBytes(int width, viz::ResourceFormat format);
- // Dies with a CRASH() if the size can not be represented as a positive
- // number of bytes.
- template <typename T>
- static T CheckedSizeInBytes(const gfx::Size& size,
- viz::ResourceFormat format);
-
- // Returns the width in bytes but may overflow or return 0. Only do this for
- // computing widths for sizes that have already been checked.
- template <typename T>
- static T UncheckedWidthInBytes(int width, viz::ResourceFormat format);
- // Returns the size in bytes but may overflow or return 0. Only do this for
- // sizes that have already been checked.
- template <typename T>
- static T UncheckedSizeInBytes(const gfx::Size& size,
- viz::ResourceFormat format);
- // Returns the width in bytes aligned but may overflow or return 0. Only do
- // this for computing widths for sizes that have already been checked.
- template <typename T>
- static T UncheckedWidthInBytesAligned(int width, viz::ResourceFormat format);
- // Returns the size in bytes aligned but may overflow or return 0. Only do
- // this for sizes that have already been checked.
- template <typename T>
- static T UncheckedSizeInBytesAligned(const gfx::Size& size,
- viz::ResourceFormat format);
-
- private:
- template <typename T>
- static inline void VerifyType();
-
- template <typename T>
- static bool VerifyFitsInBytesInternal(int width,
- int height,
- viz::ResourceFormat format,
- bool verify_size,
- bool aligned);
-
- template <typename T>
- static T BytesInternal(int width,
- int height,
- viz::ResourceFormat format,
- bool verify_size,
- bool aligned);
-
- DISALLOW_COPY_AND_ASSIGN(ResourceUtil);
-};
-
-template <typename T>
-bool ResourceUtil::VerifyWidthInBytes(int width, viz::ResourceFormat format) {
- VerifyType<T>();
- return VerifyFitsInBytesInternal<T>(width, 0, format, false, false);
-}
-
-template <typename T>
-bool ResourceUtil::VerifySizeInBytes(const gfx::Size& size,
- viz::ResourceFormat format) {
- VerifyType<T>();
- return VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
- false);
-}
-
-template <typename T>
-T ResourceUtil::CheckedWidthInBytes(int width, viz::ResourceFormat format) {
- VerifyType<T>();
- DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false));
- base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
- checked_value *= width;
- checked_value = MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
- checked_value /= 8;
- return checked_value.ValueOrDie();
-}
-
-template <typename T>
-T ResourceUtil::CheckedSizeInBytes(const gfx::Size& size,
- viz::ResourceFormat format) {
- VerifyType<T>();
- DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
- false));
- base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
- checked_value *= size.width();
- checked_value = MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
- checked_value /= 8;
- checked_value *= size.height();
- return checked_value.ValueOrDie();
-}
-
-template <typename T>
-T ResourceUtil::UncheckedWidthInBytes(int width, viz::ResourceFormat format) {
- VerifyType<T>();
- DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false));
- return BytesInternal<T>(width, 0, format, false, false);
-}
-
-template <typename T>
-T ResourceUtil::UncheckedSizeInBytes(const gfx::Size& size,
- viz::ResourceFormat format) {
- VerifyType<T>();
- DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
- false));
- return BytesInternal<T>(size.width(), size.height(), format, true, false);
-}
-
-template <typename T>
-T ResourceUtil::UncheckedWidthInBytesAligned(int width,
- viz::ResourceFormat format) {
- VerifyType<T>();
- DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, true));
- return BytesInternal<T>(width, 0, format, false, true);
-}
-
-template <typename T>
-T ResourceUtil::UncheckedSizeInBytesAligned(const gfx::Size& size,
- viz::ResourceFormat format) {
- VerifyType<T>();
- DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
- true));
- return BytesInternal<T>(size.width(), size.height(), format, true, true);
-}
-
-template <typename T>
-void ResourceUtil::VerifyType() {
- static_assert(
- std::numeric_limits<T>::is_integer && !std::is_same<T, bool>::value,
- "T must be non-bool integer type. Preferred type is size_t.");
-}
-
-template <typename T>
-bool ResourceUtil::VerifyFitsInBytesInternal(int width,
- int height,
- viz::ResourceFormat format,
- bool verify_size,
- bool aligned) {
- base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
- checked_value *= width;
- if (!checked_value.IsValid())
- return false;
-
- // Roundup bits to byte (8 bits) boundary. If width is 3 and BitsPerPixel is
- // 4, then it should return 16, so that row pixels do not get truncated.
- checked_value = MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
-
- // If aligned is true, bytes are aligned on 4-bytes boundaries for upload
- // performance, assuming that GL_PACK_ALIGNMENT or GL_UNPACK_ALIGNMENT have
- // not changed from default.
- if (aligned) {
- checked_value /= 8;
- if (!checked_value.IsValid())
- return false;
- checked_value =
- MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 4);
- checked_value *= 8;
- }
-
- if (verify_size)
- checked_value *= height;
- if (!checked_value.IsValid())
- return false;
- T value = checked_value.ValueOrDie();
- if ((value % 8) != 0)
- return false;
- return true;
-}
-
-template <typename T>
-T ResourceUtil::BytesInternal(int width,
- int height,
- viz::ResourceFormat format,
- bool verify_size,
- bool aligned) {
- T bytes = BitsPerPixel(format);
- bytes *= width;
- bytes = MathUtil::UncheckedRoundUp<T>(bytes, 8);
- bytes /= 8;
- if (aligned)
- bytes = MathUtil::UncheckedRoundUp<T>(bytes, 4);
- if (verify_size)
- bytes *= height;
-
- return bytes;
-}
-
-} // namespace cc
-
-#endif // CC_RESOURCES_RESOURCE_UTIL_H_
diff --git a/chromium/cc/resources/resource_util_unittest.cc b/chromium/cc/resources/resource_util_unittest.cc
index 8bffa6b192e..4680c0ca312 100644
--- a/chromium/cc/resources/resource_util_unittest.cc
+++ b/chromium/cc/resources/resource_util_unittest.cc
@@ -5,7 +5,7 @@
#include <stddef.h>
#include "base/logging.h"
-#include "cc/resources/resource_util.h"
+#include "components/viz/common/resources/resource_sizes.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
@@ -24,14 +24,14 @@ class ResourceUtilTest : public testing::Test {
public:
void TestVerifyWidthInBytes(int width, const TestFormat* test_formats) {
for (int i = 0; i < kTestFormats; ++i) {
- EXPECT_TRUE(ResourceUtil::VerifyWidthInBytes<size_t>(
+ EXPECT_TRUE(viz::ResourceSizes::VerifyWidthInBytes<size_t>(
width, test_formats[i].format));
}
}
void TestCheckedWidthInBytes(int width, const TestFormat* test_formats) {
for (int i = 0; i < kTestFormats; ++i) {
- size_t bytes = ResourceUtil::CheckedWidthInBytes<size_t>(
+ size_t bytes = viz::ResourceSizes::CheckedWidthInBytes<size_t>(
width, test_formats[i].format);
EXPECT_EQ(bytes, test_formats[i].expected_bytes);
}
@@ -39,7 +39,7 @@ class ResourceUtilTest : public testing::Test {
void TestUncheckedWidthInBytes(int width, const TestFormat* test_formats) {
for (int i = 0; i < kTestFormats; ++i) {
- size_t bytes = ResourceUtil::UncheckedWidthInBytes<size_t>(
+ size_t bytes = viz::ResourceSizes::UncheckedWidthInBytes<size_t>(
width, test_formats[i].format);
EXPECT_EQ(bytes, test_formats[i].expected_bytes);
}
@@ -48,7 +48,7 @@ class ResourceUtilTest : public testing::Test {
void TestUncheckedWidthInBytesAligned(int width,
const TestFormat* test_formats) {
for (int i = 0; i < kTestFormats; ++i) {
- size_t bytes = ResourceUtil::UncheckedWidthInBytesAligned<size_t>(
+ size_t bytes = viz::ResourceSizes::UncheckedWidthInBytesAligned<size_t>(
width, test_formats[i].format);
EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned);
}
@@ -57,7 +57,7 @@ class ResourceUtilTest : public testing::Test {
void TestVerifySizeInBytes(const gfx::Size& size,
const TestFormat* test_formats) {
for (int i = 0; i < kTestFormats; ++i) {
- EXPECT_TRUE(ResourceUtil::VerifySizeInBytes<size_t>(
+ EXPECT_TRUE(viz::ResourceSizes::VerifySizeInBytes<size_t>(
size, test_formats[i].format));
}
}
@@ -65,7 +65,7 @@ class ResourceUtilTest : public testing::Test {
void TestCheckedSizeInBytes(const gfx::Size& size,
const TestFormat* test_formats) {
for (int i = 0; i < kTestFormats; ++i) {
- size_t bytes = ResourceUtil::CheckedSizeInBytes<size_t>(
+ size_t bytes = viz::ResourceSizes::CheckedSizeInBytes<size_t>(
size, test_formats[i].format);
EXPECT_EQ(bytes, test_formats[i].expected_bytes);
}
@@ -74,7 +74,7 @@ class ResourceUtilTest : public testing::Test {
void TestUncheckedSizeInBytes(const gfx::Size& size,
const TestFormat* test_formats) {
for (int i = 0; i < kTestFormats; ++i) {
- size_t bytes = ResourceUtil::UncheckedSizeInBytes<size_t>(
+ size_t bytes = viz::ResourceSizes::UncheckedSizeInBytes<size_t>(
size, test_formats[i].format);
EXPECT_EQ(bytes, test_formats[i].expected_bytes);
}
@@ -83,7 +83,7 @@ class ResourceUtilTest : public testing::Test {
void TestUncheckedSizeInBytesAligned(const gfx::Size& size,
const TestFormat* test_formats) {
for (int i = 0; i < kTestFormats; ++i) {
- size_t bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
+ size_t bytes = viz::ResourceSizes::UncheckedSizeInBytesAligned<size_t>(
size, test_formats[i].format);
EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned);
}
@@ -153,18 +153,18 @@ TEST_F(ResourceUtilTest, SizeInBytes) {
TEST_F(ResourceUtilTest, WidthInBytesOverflow) {
int width = 10;
// 10 * 16 = 160 bits, overflows in char, but fits in unsigned char.
- EXPECT_FALSE(
- ResourceUtil::VerifyWidthInBytes<signed char>(width, viz::RGBA_4444));
- EXPECT_TRUE(
- ResourceUtil::VerifyWidthInBytes<unsigned char>(width, viz::RGBA_4444));
+ EXPECT_FALSE(viz::ResourceSizes::VerifyWidthInBytes<signed char>(
+ width, viz::RGBA_4444));
+ EXPECT_TRUE(viz::ResourceSizes::VerifyWidthInBytes<unsigned char>(
+ width, viz::RGBA_4444));
}
TEST_F(ResourceUtilTest, SizeInBytesOverflow) {
gfx::Size size(10, 10);
// 10 * 16 * 10 = 1600 bits, overflows in char, but fits in int.
EXPECT_FALSE(
- ResourceUtil::VerifySizeInBytes<signed char>(size, viz::RGBA_4444));
- EXPECT_TRUE(ResourceUtil::VerifySizeInBytes<int>(size, viz::RGBA_4444));
+ viz::ResourceSizes::VerifySizeInBytes<signed char>(size, viz::RGBA_4444));
+ EXPECT_TRUE(viz::ResourceSizes::VerifySizeInBytes<int>(size, viz::RGBA_4444));
}
} // namespace
diff --git a/chromium/cc/resources/shared_bitmap_id_registrar.cc b/chromium/cc/resources/shared_bitmap_id_registrar.cc
new file mode 100644
index 00000000000..8ab38867b4a
--- /dev/null
+++ b/chromium/cc/resources/shared_bitmap_id_registrar.cc
@@ -0,0 +1,35 @@
+// 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/resources/shared_bitmap_id_registrar.h"
+
+#include "cc/layers/texture_layer.h"
+
+namespace cc {
+
+SharedBitmapIdRegistration::SharedBitmapIdRegistration() = default;
+
+SharedBitmapIdRegistration::SharedBitmapIdRegistration(
+ base::WeakPtr<TextureLayer> layer_ptr,
+ const viz::SharedBitmapId& id)
+ : layer_ptr_(std::move(layer_ptr)), id_(id) {}
+
+SharedBitmapIdRegistration::~SharedBitmapIdRegistration() {
+ if (layer_ptr_)
+ layer_ptr_->UnregisterSharedBitmapId(id_);
+}
+
+SharedBitmapIdRegistration::SharedBitmapIdRegistration(
+ SharedBitmapIdRegistration&&) = default;
+
+SharedBitmapIdRegistration& SharedBitmapIdRegistration::operator=(
+ SharedBitmapIdRegistration&& other) {
+ if (layer_ptr_)
+ layer_ptr_->UnregisterSharedBitmapId(id_);
+ layer_ptr_ = std::move(other.layer_ptr_);
+ id_ = std::move(other.id_);
+ return *this;
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/shared_bitmap_id_registrar.h b/chromium/cc/resources/shared_bitmap_id_registrar.h
new file mode 100644
index 00000000000..8586a2408e7
--- /dev/null
+++ b/chromium/cc/resources/shared_bitmap_id_registrar.h
@@ -0,0 +1,72 @@
+// 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_RESOURCES_SHARED_BITMAP_ID_REGISTRAR_H_
+#define CC_RESOURCES_SHARED_BITMAP_ID_REGISTRAR_H_
+
+#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"
+
+namespace cc {
+class CrossThreadSharedBitmap;
+class SharedBitmapIdRegistration;
+class TextureLayer;
+
+// An interface exposed to clients of TextureLayer for registering
+// SharedBitmapIds that they will be using in viz::TransferableResources given
+// to the TextureLayer. SharedBitmapId-SharedMemory pairs registered as such are
+// then given to the display compositor, and the mapping between the pair is
+// kept valid while the returned SharedBitmapIdRegistration is kept alive.
+//
+// These mappings are per-layer-tree. So if a client has multiple TextureLayers
+// in the same tree, and wants to use the SharedBitmapId in more than one of
+// them over time, it still only should register with a single TextureLayer. But
+// if the TextureLayer is removed from the tree, they would need to be
+// registered with another TextureLayer that is in each tree where they are
+// being used.
+class CC_EXPORT SharedBitmapIdRegistrar {
+ public:
+ virtual ~SharedBitmapIdRegistrar() = default;
+ virtual SharedBitmapIdRegistration RegisterSharedBitmapId(
+ const viz::SharedBitmapId& id,
+ scoped_refptr<CrossThreadSharedBitmap> bitmap) = 0;
+};
+
+// A scoped object that maintains a mapping of SharedBitmapId to SharedMemory
+// that was registered through SharedBitmapIdRegistrar for the display
+// compositor. Keep this object alive while the SharedBitmapId may be used
+// in viz::TransferableResources given to the TextureLayer. Typically that means
+// as long as the client keeps the SharedMemory alive with a reference to the
+// CrossThreadSharedBitmap, which it should keep alive at least until the
+// TextureLayer calls back to the ReleaseCallback indicating the display
+// compositor is no longer using the resource. When this object is destroyed, or
+// assigned to, then the mapping registration will be dropped from the display
+// compositor, and the SharedBitmapId will no longer be able to be used in the
+// TextureLayer.
+class CC_EXPORT SharedBitmapIdRegistration {
+ public:
+ SharedBitmapIdRegistration();
+ ~SharedBitmapIdRegistration();
+
+ SharedBitmapIdRegistration(SharedBitmapIdRegistration&&);
+ SharedBitmapIdRegistration& operator=(SharedBitmapIdRegistration&&);
+
+ private:
+ // Constructed by TextureLayer only, then held by the client as long
+ // as they wish to
+ friend TextureLayer;
+ SharedBitmapIdRegistration(base::WeakPtr<TextureLayer> layer_ptr,
+ const viz::SharedBitmapId& id);
+
+ base::WeakPtr<TextureLayer> layer_ptr_;
+ viz::SharedBitmapId id_;
+
+ DISALLOW_COPY_AND_ASSIGN(SharedBitmapIdRegistration);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_SHARED_BITMAP_ID_REGISTRAR_H_
diff --git a/chromium/cc/resources/video_resource_updater.cc b/chromium/cc/resources/video_resource_updater.cc
index dcf6ea012ca..6b3b19215d7 100644
--- a/chromium/cc/resources/video_resource_updater.cc
+++ b/chromium/cc/resources/video_resource_updater.cc
@@ -8,20 +8,31 @@
#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 "cc/resources/resource_util.h"
+#include "cc/trees/layer_tree_frame_sink.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 "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"
@@ -31,12 +42,16 @@
#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/trace_util.h"
namespace cc {
-
namespace {
-VideoFrameExternalResources::ResourceType ExternalResourceTypeForHardwarePlanes(
+// 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,
@@ -51,21 +66,21 @@ VideoFrameExternalResources::ResourceType ExternalResourceTypeForHardwarePlanes(
switch (target) {
case GL_TEXTURE_EXTERNAL_OES:
if (use_stream_video_draw_quad)
- return VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
+ return VideoFrameResourceType::STREAM_TEXTURE;
FALLTHROUGH;
case GL_TEXTURE_2D:
return (format == media::PIXEL_FORMAT_XRGB)
- ? VideoFrameExternalResources::RGB_RESOURCE
- : VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE;
+ ? VideoFrameResourceType::RGB
+ : VideoFrameResourceType::RGBA_PREMULTIPLIED;
case GL_TEXTURE_RECTANGLE_ARB:
- return VideoFrameExternalResources::RGB_RESOURCE;
+ return VideoFrameResourceType::RGB;
default:
NOTREACHED();
break;
}
break;
case media::PIXEL_FORMAT_I420:
- return VideoFrameExternalResources::YUV_RESOURCE;
+ return VideoFrameResourceType::YUV;
case media::PIXEL_FORMAT_NV12:
DCHECK(target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_2D ||
target == GL_TEXTURE_RECTANGLE_ARB)
@@ -73,10 +88,10 @@ VideoFrameExternalResources::ResourceType ExternalResourceTypeForHardwarePlanes(
<< target;
// Single plane textures can be sampled as RGB.
if (num_textures > 1)
- return VideoFrameExternalResources::YUV_RESOURCE;
+ return VideoFrameResourceType::YUV;
*buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
- return VideoFrameExternalResources::RGB_RESOURCE;
+ return VideoFrameResourceType::RGB;
case media::PIXEL_FORMAT_YV12:
case media::PIXEL_FORMAT_I422:
case media::PIXEL_FORMAT_I444:
@@ -99,7 +114,7 @@ VideoFrameExternalResources::ResourceType ExternalResourceTypeForHardwarePlanes(
case media::PIXEL_FORMAT_UNKNOWN:
break;
}
- return VideoFrameExternalResources::NONE;
+ return VideoFrameResourceType::NONE;
}
class SyncTokenClientImpl : public media::VideoFrame::SyncTokenClient {
@@ -138,162 +153,11 @@ void GenerateCompositorSyncToken(gpu::gles2::GLES2Interface* gl,
gl->GenUnverifiedSyncTokenCHROMIUM(sync_token->GetData());
}
-} // namespace
-
-VideoResourceUpdater::PlaneResource::PlaneResource(
- unsigned int resource_id,
- const gfx::Size& resource_size,
- viz::ResourceFormat resource_format,
- gpu::Mailbox mailbox)
- : resource_id_(resource_id),
- resource_size_(resource_size),
- resource_format_(resource_format),
- mailbox_(mailbox) {}
-
-VideoResourceUpdater::PlaneResource::PlaneResource(const PlaneResource& other) =
- default;
-
-bool VideoResourceUpdater::PlaneResource::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;
-}
-
-void VideoResourceUpdater::PlaneResource::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;
-}
-
-VideoFrameExternalResources::VideoFrameExternalResources() = default;
-VideoFrameExternalResources::~VideoFrameExternalResources() = default;
-
-VideoFrameExternalResources::VideoFrameExternalResources(
- VideoFrameExternalResources&& other) = default;
-VideoFrameExternalResources& VideoFrameExternalResources::operator=(
- VideoFrameExternalResources&& other) = default;
-
-VideoResourceUpdater::VideoResourceUpdater(
- viz::ContextProvider* context_provider,
- LayerTreeResourceProvider* resource_provider,
- bool use_stream_video_draw_quad)
- : context_provider_(context_provider),
- resource_provider_(resource_provider),
- use_stream_video_draw_quad_(use_stream_video_draw_quad),
- weak_ptr_factory_(this) {}
-
-VideoResourceUpdater::~VideoResourceUpdater() {
- for (const PlaneResource& plane_resource : all_resources_)
- resource_provider_->DeleteResource(plane_resource.resource_id());
-}
-
-VideoResourceUpdater::ResourceList::iterator
-VideoResourceUpdater::RecycleOrAllocateResource(
- const gfx::Size& resource_size,
- viz::ResourceFormat resource_format,
- const gfx::ColorSpace& color_space,
- bool software_resource,
- int unique_id,
- int plane_index) {
- ResourceList::iterator recyclable_resource = all_resources_.end();
- for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) {
- // 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 && it->Matches(unique_id, plane_index)) {
- DCHECK(it->resource_size() == resource_size);
- DCHECK(it->resource_format() == resource_format);
- DCHECK(it->mailbox().IsZero() == software_resource);
- return it;
- }
-
- // 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.
- // Resources backed by SharedMemory are not ref-counted, unlike mailboxes,
- // so the definition of |in_use| must take this into account. Full
- // discussion in codereview.chromium.org/145273021.
- const bool in_use =
- it->has_refs() ||
- (software_resource &&
- resource_provider_->InUseByConsumer(it->resource_id()));
-
- if (!in_use && it->resource_size() == resource_size &&
- it->resource_format() == resource_format &&
- it->mailbox().IsZero() == software_resource) {
- recyclable_resource = it;
- }
- }
-
- if (recyclable_resource != all_resources_.end())
- return recyclable_resource;
-
- // There was nothing available to reuse or recycle. Allocate a new resource.
- return AllocateResource(resource_size, resource_format, color_space,
- software_resource);
-}
-
-VideoResourceUpdater::ResourceList::iterator
-VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size,
- viz::ResourceFormat format,
- const gfx::ColorSpace& color_space,
- bool software_resource) {
- viz::ResourceId resource_id;
- gpu::Mailbox mailbox;
-
- // TODO(danakj): Abstract out hw/sw resource create/delete from
- // ResourceProvider and stop using ResourceProvider in this class.
- if (software_resource) {
- DCHECK_EQ(format, viz::RGBA_8888);
- resource_id =
- resource_provider_->CreateBitmapResource(plane_size, color_space);
- } else {
- DCHECK(context_provider_);
-
- resource_id = resource_provider_->CreateGpuTextureResource(
- plane_size, viz::ResourceTextureHint::kDefault, format, color_space);
-
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
-
- gl->GenMailboxCHROMIUM(mailbox.name);
- LayerTreeResourceProvider::ScopedWriteLockGL lock(resource_provider_,
- resource_id);
- gl->ProduceTextureDirectCHROMIUM(
- lock.GetTexture(),
- mailbox.name);
- }
- all_resources_.push_front(
- PlaneResource(resource_id, plane_size, format, mailbox));
- return all_resources_.begin();
-}
-
-void VideoResourceUpdater::DeleteResource(ResourceList::iterator resource_it) {
- DCHECK(!resource_it->has_refs());
- resource_provider_->DeleteResource(resource_it->resource_id());
- all_resources_.erase(resource_it);
-}
-
-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));
-}
-
// For frames that we receive in software format, determine the dimensions of
// each plane in the frame.
-static gfx::Size SoftwarePlaneDimension(media::VideoFrame* input_frame,
- bool software_compositor,
- size_t plane_index) {
+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;
@@ -305,283 +169,197 @@ static gfx::Size SoftwarePlaneDimension(media::VideoFrame* input_frame,
return gfx::Size(plane_width, plane_height);
}
-VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
- scoped_refptr<media::VideoFrame> video_frame) {
- TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes");
- const media::VideoPixelFormat input_frame_format = video_frame->format();
+} // namespace
- size_t bits_per_channel = video_frame->BitDepth();
+VideoFrameExternalResources::VideoFrameExternalResources() = default;
+VideoFrameExternalResources::~VideoFrameExternalResources() = default;
- // Only YUV and Y16 software video frames are supported.
- DCHECK(media::IsYuvPlanar(input_frame_format) ||
- input_frame_format == media::PIXEL_FORMAT_Y16);
+VideoFrameExternalResources::VideoFrameExternalResources(
+ VideoFrameExternalResources&& other) = default;
+VideoFrameExternalResources& VideoFrameExternalResources::operator=(
+ VideoFrameExternalResources&& other) = default;
- const bool software_compositor = context_provider_ == nullptr;
+// 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;
+ }
- 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 {
- // Can be composited directly from yuv planes.
- output_resource_format =
- resource_provider_->YuvResourceFormat(bits_per_channel);
+ // 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;
}
- // 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;
+ // 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_; }
- size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_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; }
- // 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;
+ 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);
+};
- // 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();
+class VideoResourceUpdater::SoftwarePlaneResource
+ : public VideoResourceUpdater::PlaneResource {
+ public:
+ SoftwarePlaneResource(uint32_t plane_resource_id,
+ const gfx::Size& size,
+ LayerTreeFrameSink* layer_tree_frame_sink)
+ : PlaneResource(plane_resource_id,
+ size,
+ viz::ResourceFormat::RGBA_8888,
+ /*is_software=*/true),
+ layer_tree_frame_sink_(layer_tree_frame_sink),
+ shared_bitmap_id_(viz::SharedBitmap::GenerateId()) {
+ DCHECK(layer_tree_frame_sink_);
+
+ // 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);
+ layer_tree_frame_sink_->DidAllocateSharedBitmap(std::move(handle),
+ shared_bitmap_id_);
}
-
- // Drop recycled resources that are the wrong format.
- for (auto it = all_resources_.begin(); it != all_resources_.end();) {
- if (!it->has_refs() && it->resource_format() != output_resource_format)
- DeleteResource(it++);
- else
- ++it;
+ ~SoftwarePlaneResource() override {
+ layer_tree_frame_sink_->DidDeleteSharedBitmap(shared_bitmap_id_);
}
- const int max_resource_size = resource_provider_->max_texture_size();
- std::vector<ResourceList::iterator> plane_resources;
- for (size_t i = 0; i < output_plane_count; ++i) {
- gfx::Size output_plane_resource_size =
- SoftwarePlaneDimension(video_frame.get(), software_compositor, i);
- 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. Clean up and return an empty
- // external resources.
- for (ResourceList::iterator resource_it : plane_resources)
- resource_it->remove_ref();
- return VideoFrameExternalResources();
- }
-
- ResourceList::iterator resource_it = RecycleOrAllocateResource(
- output_plane_resource_size, output_resource_format, output_color_space,
- software_compositor, video_frame->unique_id(), i);
-
- resource_it->add_ref();
- plane_resources.push_back(resource_it);
+ const viz::SharedBitmapId& shared_bitmap_id() const {
+ return shared_bitmap_id_;
}
+ void* pixels() { return shared_memory_->memory(); }
- 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);
- DCHECK(!software_compositor ||
- plane_resource.resource_id() > viz::kInvalidResourceId);
- DCHECK_EQ(software_compositor, plane_resource.mailbox().IsZero());
-
- 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_.reset(new media::PaintCanvasVideoRenderer);
-
- LayerTreeResourceProvider::ScopedWriteLockSoftware lock(
- resource_provider_, plane_resource.resource_id());
- SkiaPaintCanvas canvas(lock.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 {
- size_t bytes_per_row = ResourceUtil::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)
- upload_pixels_.resize(needed_size);
-
- media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
- video_frame.get(), &upload_pixels_[0], bytes_per_row);
-
- resource_provider_->CopyToResource(plane_resource.resource_id(),
- &upload_pixels_[0],
- plane_resource.resource_size());
- }
- plane_resource.SetUniqueId(video_frame->unique_id(), 0);
- }
+ // Returns a memory dump GUID consistent across processes.
+ base::UnguessableToken GetSharedMemoryGuid() const {
+ return shared_memory_->mapped_id();
+ }
- if (software_compositor) {
- external_resources.software_resource = plane_resource.resource_id();
- external_resources.software_release_callback =
- base::Bind(&RecycleResource, weak_ptr_factory_.GetWeakPtr(),
- plane_resource.resource_id());
- external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
- } else {
- gpu::SyncToken sync_token;
- GenerateCompositorSyncToken(context_provider_->ContextGL(), &sync_token);
+ private:
+ LayerTreeFrameSink* const layer_tree_frame_sink_;
+ const viz::SharedBitmapId shared_bitmap_id_;
+ std::unique_ptr<base::SharedMemory> shared_memory_;
- GLuint target = resource_provider_->GetResourceTextureTarget(
- plane_resource.resource_id());
- auto transfer_resource = viz::TransferableResource::MakeGL(
- plane_resource.mailbox(), GL_LINEAR, target, sync_token);
- transfer_resource.color_space = output_color_space;
+ DISALLOW_COPY_AND_ASSIGN(SoftwarePlaneResource);
+};
- external_resources.resources.push_back(std::move(transfer_resource));
- external_resources.release_callbacks.push_back(
- base::Bind(&RecycleResource, weak_ptr_factory_.GetWeakPtr(),
- plane_resource.resource_id()));
- external_resources.type = VideoFrameExternalResources::RGBA_RESOURCE;
- }
- return external_resources;
+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);
}
-
- const viz::ResourceFormat yuv_resource_format =
- resource_provider_->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;
+ ~HardwarePlaneResource() override {
+ context_provider_->ContextGL()->DeleteTextures(1, &allocation_.texture_id);
}
- // We need to transfer data from |video_frame| to the plane resources.
- for (size_t i = 0; i < plane_resources.size(); ++i) {
- PlaneResource& plane_resource = *plane_resources[i];
- // 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 = ResourceUtil::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));
+ 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; }
- // 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)
- upload_pixels_.resize(needed_size);
+ private:
+ viz::ContextProvider* const context_provider_;
+ const gpu::Mailbox mailbox_;
+ const viz::TextureAllocation allocation_;
- 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());
- }
+ DISALLOW_COPY_AND_ASSIGN(HardwarePlaneResource);
+};
- pixels = &upload_pixels_[0];
- }
+VideoResourceUpdater::SoftwarePlaneResource*
+VideoResourceUpdater::PlaneResource::AsSoftware() {
+ DCHECK(is_software_);
+ return static_cast<SoftwarePlaneResource*>(this);
+}
- resource_provider_->CopyToResource(plane_resource.resource_id(), pixels,
- resource_size_pixels);
- plane_resource.SetUniqueId(video_frame->unique_id(), i);
- }
+VideoResourceUpdater::HardwarePlaneResource*
+VideoResourceUpdater::PlaneResource::AsHardware() {
+ DCHECK(!is_software_);
+ return static_cast<HardwarePlaneResource*>(this);
+}
- // Set the sync token otherwise resource is assumed to be synchronized.
- gpu::SyncToken sync_token;
- GenerateCompositorSyncToken(context_provider_->ContextGL(), &sync_token);
+VideoResourceUpdater::VideoResourceUpdater(
+ viz::ContextProvider* context_provider,
+ LayerTreeFrameSink* layer_tree_frame_sink,
+ LayerTreeResourceProvider* resource_provider,
+ bool use_stream_video_draw_quad,
+ bool use_gpu_memory_buffer_resources)
+ : context_provider_(context_provider),
+ layer_tree_frame_sink_(layer_tree_frame_sink),
+ resource_provider_(resource_provider),
+ use_stream_video_draw_quad_(use_stream_video_draw_quad),
+ use_gpu_memory_buffer_resources_(use_gpu_memory_buffer_resources),
+ tracing_id_(g_next_video_resource_updater_id.GetNext()),
+ weak_ptr_factory_(this) {
+ DCHECK(context_provider_ || layer_tree_frame_sink_);
- for (size_t i = 0; i < plane_resources.size(); ++i) {
- PlaneResource& plane_resource = *plane_resources[i];
- GLuint target = resource_provider_->GetResourceTextureTarget(
- plane_resource.resource_id());
- auto transfer_resource = viz::TransferableResource::MakeGL(
- plane_resource.mailbox(), GL_LINEAR, target, sync_token);
- transfer_resource.color_space = output_color_space;
- external_resources.resources.push_back(std::move(transfer_resource));
- external_resources.release_callbacks.push_back(
- base::Bind(&RecycleResource, weak_ptr_factory_.GetWeakPtr(),
- plane_resource.resource_id()));
- }
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ this, "cc::VideoResourceUpdater", base::ThreadTaskRunnerHandle::Get());
+}
- external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
- return external_resources;
+VideoResourceUpdater::~VideoResourceUpdater() {
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ this);
}
void VideoResourceUpdater::ObtainFrameResources(
@@ -590,43 +368,31 @@ void VideoResourceUpdater::ObtainFrameResources(
CreateExternalResourcesFromVideoFrame(video_frame);
frame_resource_type_ = external_resources.type;
- if (external_resources.type ==
- VideoFrameExternalResources::SOFTWARE_RESOURCE) {
- DCHECK_GT(external_resources.software_resource, viz::kInvalidResourceId);
- software_resource_ = external_resources.software_resource;
- software_release_callback_ =
- std::move(external_resources.software_release_callback);
- } else {
+ 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());
- ResourceProvider::ResourceIdArray resource_ids;
- resource_ids.reserve(external_resources.resources.size());
- for (size_t i = 0; i < external_resources.resources.size(); ++i) {
- unsigned resource_id = resource_provider_->ImportResource(
- external_resources.resources[i],
- viz::SingleReleaseCallback::Create(
- std::move(external_resources.release_callbacks[i])));
- frame_resources_.push_back(
- FrameResource(resource_id, external_resources.resources[i].size));
- resource_ids.push_back(resource_id);
- }
+ 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() {
- if (frame_resource_type_ == VideoFrameExternalResources::SOFTWARE_RESOURCE) {
- DCHECK_GT(software_resource_, viz::kInvalidResourceId);
- std::move(software_release_callback_).Run(gpu::SyncToken(), false);
- software_resource_ = viz::kInvalidResourceId;
- } else {
- for (size_t i = 0; i < frame_resources_.size(); ++i)
- resource_provider_->RemoveImportedResource(frame_resources_[i].id);
- frame_resources_.clear();
- }
+ for (auto& frame_resource : frame_resources_)
+ resource_provider_->RemoveImportedResource(frame_resource.id);
+ frame_resources_.clear();
}
void VideoResourceUpdater::AppendQuads(viz::RenderPass* render_pass,
@@ -660,28 +426,7 @@ void VideoResourceUpdater::AppendQuads(viz::RenderPass* render_pass,
static_cast<float>(visible_rect.height()) / coded_size.height();
switch (frame_resource_type_) {
- // TODO(danakj): Remove this, hide it in the hardware path.
- case VideoFrameExternalResources::SOFTWARE_RESOURCE: {
- DCHECK_EQ(frame_resources_.size(), 0u);
- DCHECK_GT(software_resource_, viz::kInvalidResourceId);
- bool premultiplied_alpha = true;
- 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,
- software_resource_, premultiplied_alpha, uv_top_left, uv_bottom_right,
- SK_ColorTRANSPARENT, opacity, flipped, nearest_neighbor, false);
- for (viz::ResourceId resource_id : texture_quad->resources) {
- resource_provider_->ValidateResource(resource_id);
- }
- break;
- }
- case VideoFrameExternalResources::YUV_RESOURCE: {
+ case VideoFrameResourceType::YUV: {
const gfx::Size ya_tex_size = coded_size;
int u_width = media::VideoFrame::Columns(
@@ -730,23 +475,22 @@ void VideoResourceUpdater::AppendQuads(viz::RenderPass* render_pass,
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->require_overlay =
+ frame->metadata()->IsTrue(media::VideoFrameMetadata::REQUIRE_OVERLAY);
for (viz::ResourceId resource_id : yuv_video_quad->resources) {
resource_provider_->ValidateResource(resource_id);
}
break;
}
- case VideoFrameExternalResources::RGBA_RESOURCE:
- case VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE:
- case VideoFrameExternalResources::RGB_RESOURCE: {
+ 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_ ==
- VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE;
+ 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};
@@ -765,7 +509,7 @@ void VideoResourceUpdater::AppendQuads(viz::RenderPass* render_pass,
}
break;
}
- case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
+ case VideoFrameResourceType::STREAM_TEXTURE: {
DCHECK_EQ(frame_resources_.size(), 1u);
if (frame_resources_.size() < 1u)
break;
@@ -781,30 +525,94 @@ void VideoResourceUpdater::AppendQuads(viz::RenderPass* render_pass,
}
break;
}
- case VideoFrameExternalResources::NONE:
+ case VideoFrameResourceType::NONE:
NOTIMPLEMENTED();
break;
}
}
-// static
-void VideoResourceUpdater::ReturnTexture(
- base::WeakPtr<VideoResourceUpdater> updater,
- const scoped_refptr<media::VideoFrame>& video_frame,
- const gpu::SyncToken& sync_token,
- bool lost_resource) {
- // TODO(dshwang) this case should be forwarded to the decoder as lost
- // resource.
- if (lost_resource || !updater.get())
- return;
- // The video frame will insert a wait on the previous release sync token.
- SyncTokenClientImpl client(updater->context_provider_->ContextGL(),
- sync_token);
- video_frame->UpdateReleaseSyncToken(&client);
+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));
+}
+
+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, layer_tree_frame_sink_));
+ } 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();
}
-// Create a copy of a texture-backed source video frame in a new GL_TEXTURE_2D
-// texture.
void VideoResourceUpdater::CopyHardwarePlane(
media::VideoFrame* video_frame,
const gfx::ColorSpace& resource_color_space,
@@ -813,21 +621,19 @@ void VideoResourceUpdater::CopyHardwarePlane(
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.
- const viz::ResourceFormat copy_target_format = viz::ResourceFormat::RGBA_8888;
+ 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.
- VideoResourceUpdater::ResourceList::iterator resource =
- RecycleOrAllocateResource(output_plane_resource_size, copy_target_format,
- resource_color_space, false, no_unique_id,
- no_plane_index);
- resource->add_ref();
-
- LayerTreeResourceProvider::ScopedWriteLockGL lock(resource_provider_,
- resource->resource_id());
- DCHECK_EQ(
- resource_provider_->GetResourceTextureTarget(resource->resource_id()),
- (GLenum)GL_TEXTURE_2D);
+ 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();
@@ -835,23 +641,25 @@ void VideoResourceUpdater::CopyHardwarePlane(
uint32_t src_texture_id =
gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name);
gl->CopySubTextureCHROMIUM(
- src_texture_id, 0, GL_TEXTURE_2D, lock.GetTexture(), 0, 0, 0, 0, 0,
- output_plane_resource_size.width(), output_plane_resource_size.height(),
- false, false, false);
+ 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 transfer_resource = viz::TransferableResource::MakeGL(
- resource->mailbox(), GL_LINEAR, GL_TEXTURE_2D, sync_token);
- transfer_resource.color_space = resource_color_space;
- external_resources->resources.push_back(std::move(transfer_resource));
+ 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::Bind(&RecycleResource, weak_ptr_factory_.GetWeakPtr(),
- resource->resource_id()));
+ external_resources->release_callbacks.push_back(base::BindOnce(
+ &VideoResourceUpdater::RecycleResource, weak_ptr_factory_.GetWeakPtr(),
+ hardware_resource->plane_resource_id()));
}
VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
@@ -876,15 +684,14 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
external_resources.type = ExternalResourceTypeForHardwarePlanes(
video_frame->format(), target, video_frame->NumTextures(), &buffer_format,
use_stream_video_draw_quad_);
- if (external_resources.type == VideoFrameExternalResources::NONE) {
+ if (external_resources.type == VideoFrameResourceType::NONE) {
DLOG(ERROR) << "Unsupported Texture format"
<< media::VideoPixelFormatToString(video_frame->format());
return external_resources;
}
- if (external_resources.type == VideoFrameExternalResources::RGB_RESOURCE ||
- external_resources.type == VideoFrameExternalResources::RGBA_RESOURCE ||
- external_resources.type ==
- VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE) {
+ if (external_resources.type == VideoFrameResourceType::RGB ||
+ external_resources.type == VideoFrameResourceType::RGBA ||
+ external_resources.type == VideoFrameResourceType::RGBA_PREMULTIPLIED) {
resource_color_space = resource_color_space.GetAsFullRangeRGB();
}
@@ -916,44 +723,407 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
media::VideoFrameMetadata::WANTS_PROMOTION_HINT);
#endif
external_resources.resources.push_back(std::move(transfer_resource));
- external_resources.release_callbacks.push_back(base::Bind(
- &ReturnTexture, weak_ptr_factory_.GetWeakPtr(), video_frame));
+ external_resources.release_callbacks.push_back(
+ base::BindOnce(&VideoResourceUpdater::ReturnTexture,
+ weak_ptr_factory_.GetWeakPtr(), video_frame));
}
}
return external_resources;
}
-// static
-void VideoResourceUpdater::RecycleResource(
- base::WeakPtr<VideoResourceUpdater> updater,
- viz::ResourceId resource_id,
+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 {
+ // Can be composited directly from yuv planes.
+ output_resource_format =
+ resource_provider_->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();
+ }
+
+ // Drop recycled resources that are the wrong format.
+ auto can_delete_resource_fn =
+ [output_resource_format](const std::unique_ptr<PlaneResource>& resource) {
+ return !resource->has_refs() &&
+ resource->resource_format() != output_resource_format;
+ };
+ base::EraseIf(all_resources_, can_delete_resource_fn);
+ // TODO(kylechar): Delete resources that are the wrong size for all output
+ // planes.
+
+ const int max_resource_size = resource_provider_->max_texture_size();
+ std::vector<PlaneResource*> plane_resources;
+ for (size_t i = 0; i < output_plane_count; ++i) {
+ gfx::Size output_plane_resource_size =
+ SoftwarePlaneDimension(video_frame.get(), software_compositor(), i);
+ 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. Clean up and return an empty
+ // external resources.
+ for (auto* plane_resource : plane_resources)
+ plane_resource->remove_ref();
+ return VideoFrameExternalResources();
+ }
+
+ PlaneResource* plane_resource = RecycleOrAllocateResource(
+ output_plane_resource_size, output_resource_format, output_color_space,
+ video_frame->unique_id(), i);
+
+ plane_resource->add_ref();
+ plane_resources.push_back(plane_resource);
+ }
+
+ 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(), 0 /* sequence_number */,
+ 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 =
+ resource_provider_->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) {
- if (!updater.get()) {
- // Resource was already deleted.
+ // TODO(dshwang): Forward to the decoder as a lost resource.
+ if (lost_resource)
return;
- }
- const ResourceList::iterator resource_it = std::find_if(
- updater->all_resources_.begin(), updater->all_resources_.end(),
- [resource_id](const PlaneResource& plane_resource) {
- return plane_resource.resource_id() == resource_id;
- });
- if (resource_it == updater->all_resources_.end())
+
+ // 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;
- viz::ContextProvider* context_provider = updater->context_provider_;
- if (context_provider && sync_token.HasData()) {
- context_provider->ContextGL()->WaitSyncTokenCHROMIUM(
+ if (context_provider_ && sync_token.HasData()) {
+ context_provider_->ContextGL()->WaitSyncTokenCHROMIUM(
sync_token.GetConstData());
}
if (lost_resource) {
- resource_it->clear_refs();
- updater->DeleteResource(resource_it);
- return;
+ 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);
+ }
}
- resource_it->remove_ref();
+ return true;
}
} // namespace cc
diff --git a/chromium/cc/resources/video_resource_updater.h b/chromium/cc/resources/video_resource_updater.h
index c422902acfe..6d152ef2d85 100644
--- a/chromium/cc/resources/video_resource_updater.h
+++ b/chromium/cc/resources/video_resource_updater.h
@@ -16,6 +16,7 @@
#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"
@@ -40,31 +41,26 @@ class RenderPass;
}
namespace cc {
+class LayerTreeFrameSink;
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:
- // Specifies what type of data is contained in the mailboxes, as well as how
- // many mailboxes will be present.
- enum ResourceType {
- NONE,
- YUV_RESOURCE,
- RGB_RESOURCE,
- RGBA_PREMULTIPLIED_RESOURCE,
- RGBA_RESOURCE,
- STREAM_TEXTURE_RESOURCE,
-
- SOFTWARE_RESOURCE
- };
- ResourceType type = NONE;
+ VideoFrameResourceType type = VideoFrameResourceType::NONE;
std::vector<viz::TransferableResource> resources;
std::vector<viz::ReleaseCallback> release_callbacks;
- // TODO(danakj): Remove these and use TransferableResources to send
- // software things too.
- unsigned software_resource = viz::kInvalidResourceId;
- viz::ReleaseCallback software_release_callback;
-
// 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;
@@ -79,20 +75,30 @@ class CC_EXPORT VideoFrameExternalResources {
// VideoResourceUpdater is used by the video system to produce frame content as
// resources consumable by the compositor.
-class CC_EXPORT VideoResourceUpdater {
+class CC_EXPORT VideoResourceUpdater
+ : public base::trace_event::MemoryDumpProvider {
public:
+ // For GPU compositing |context_provider| should be provided and for software
+ // compositing |layer_tree_frame_sink| should be provided. If there is a
+ // non-null |context_provider| we assume GPU compositing.
+ // TODO(kylechar): Don't use LayerTreeFrameSink for the software compositing
+ // path. The UseSurfaceLayerForVideo path isn't compatible with this. We can
+ // maybe use mojom::CompositorFrameSink instead.
VideoResourceUpdater(viz::ContextProvider* context_provider,
+ LayerTreeFrameSink* layer_tree_frame_sink,
LayerTreeResourceProvider* resource_provider,
- bool use_stream_video_draw_quad);
- ~VideoResourceUpdater();
-
- VideoFrameExternalResources CreateExternalResourcesFromVideoFrame(
- scoped_refptr<media::VideoFrame> video_frame);
-
- void SetUseR16ForTesting(bool use_r16_for_testing) {
- use_r16_for_testing_ = use_r16_for_testing;
- }
-
+ bool use_stream_video_draw_quad,
+ bool use_gpu_memory_buffer_resources);
+
+ ~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 SharedBitmap
+ // 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,
@@ -107,56 +113,23 @@ class CC_EXPORT VideoResourceUpdater {
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);
+
private:
- class PlaneResource {
- public:
- PlaneResource(unsigned resource_id,
- const gfx::Size& resource_size,
- viz::ResourceFormat resource_format,
- gpu::Mailbox mailbox);
- PlaneResource(const PlaneResource& other);
-
- // Returns true if this resource matches the unique identifiers of another
- // VideoFrame resource.
- bool Matches(int unique_frame_id, size_t 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);
-
- // Accessors for resource identifiers provided at construction time.
- unsigned resource_id() const { return resource_id_; }
- const gfx::Size& resource_size() const { return resource_size_; }
- viz::ResourceFormat resource_format() const { return resource_format_; }
- const gpu::Mailbox& mailbox() const { return mailbox_; }
-
- // 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:
- // The balance between the number of times this resource has been returned
- // from CreateForSoftwarePlanes vs released in RecycleResource.
- 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;
-
- const unsigned resource_id_;
- const gfx::Size resource_size_;
- const viz::ResourceFormat resource_format_;
- const gpu::Mailbox mailbox_;
+ 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;
};
- // This needs to be a container where iterators can be erased without
- // invalidating other iterators.
- typedef std::list<PlaneResource> ResourceList;
+ 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
@@ -166,64 +139,72 @@ class CC_EXPORT VideoResourceUpdater {
// used for reading, and so is returned even if it is still referenced.
// Passing -1 for |plane_index| avoids returning referenced
// resources.
- ResourceList::iterator RecycleOrAllocateResource(
- const gfx::Size& resource_size,
- viz::ResourceFormat resource_format,
- const gfx::ColorSpace& color_space,
- bool software_resource,
- int unique_id,
- int plane_index);
- ResourceList::iterator AllocateResource(const gfx::Size& plane_size,
- viz::ResourceFormat format,
- const gfx::ColorSpace& color_space,
- bool software_resource);
- void DeleteResource(ResourceList::iterator resource_it);
+ 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);
- static void RecycleResource(base::WeakPtr<VideoResourceUpdater> updater,
- unsigned resource_id,
- const gpu::SyncToken& sync_token,
- bool lost_resource);
- static void ReturnTexture(base::WeakPtr<VideoResourceUpdater> updater,
- const scoped_refptr<media::VideoFrame>& video_frame,
- const gpu::SyncToken& sync_token,
- bool lost_resource);
-
- viz::ContextProvider* context_provider_;
- LayerTreeResourceProvider* resource_provider_;
+ 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_;
+ LayerTreeFrameSink* const layer_tree_frame_sink_;
+ LayerTreeResourceProvider* const resource_provider_;
const bool use_stream_video_draw_quad_;
+ const bool use_gpu_memory_buffer_resources_;
+ 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_;
- bool use_r16_for_testing_ = false;
- VideoFrameExternalResources::ResourceType frame_resource_type_;
- // TODO(danakj): Remove these, use TransferableResource for software path too.
- unsigned software_resource_ = viz::kInvalidResourceId;
- // Called once for |software_resource_|.
- viz::ReleaseCallback software_release_callback_;
+ VideoFrameResourceType frame_resource_type_;
float frame_resource_offset_;
float frame_resource_multiplier_;
uint32_t frame_bits_per_channel_;
- struct FrameResource {
- FrameResource(viz::ResourceId id, gfx::Size size_in_pixels)
- : id(id), size_in_pixels(size_in_pixels) {}
- viz::ResourceId id;
- gfx::Size size_in_pixels;
- };
+ // Resources that will be placed into quads by the next call to
+ // AppendDrawQuads().
std::vector<FrameResource> frame_resources_;
- // Recycle resources so that we can reduce the number of allocations and
- // data transfers.
- ResourceList all_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_;
diff --git a/chromium/cc/resources/video_resource_updater_unittest.cc b/chromium/cc/resources/video_resource_updater_unittest.cc
index acc9ae843e6..17b44064587 100644
--- a/chromium/cc/resources/video_resource_updater_unittest.cc
+++ b/chromium/cc/resources/video_resource_updater_unittest.cc
@@ -8,12 +8,11 @@
#include <stdint.h>
#include "base/bind.h"
-#include "base/memory/ptr_util.h"
#include "cc/resources/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_shared_bitmap_manager.h"
#include "components/viz/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "media/base/video_frame.h"
@@ -69,22 +68,6 @@ class WebGraphicsContext3DUploadCounter : public viz::TestWebGraphicsContext3D {
int created_texture_count_;
};
-class SharedBitmapManagerAllocationCounter
- : public viz::TestSharedBitmapManager {
- public:
- std::unique_ptr<viz::SharedBitmap> AllocateSharedBitmap(
- const gfx::Size& size) override {
- ++allocation_count_;
- return TestSharedBitmapManager::AllocateSharedBitmap(size);
- }
-
- int AllocationCount() { return allocation_count_; }
- void ResetAllocationCount() { allocation_count_ = 0; }
-
- private:
- int allocation_count_;
-};
-
class VideoResourceUpdaterTest : public testing::Test {
protected:
VideoResourceUpdaterTest() {
@@ -98,17 +81,31 @@ class VideoResourceUpdaterTest : public testing::Test {
context_provider_->BindToCurrentThread();
}
+ // testing::Test implementation.
void SetUp() override {
testing::Test::SetUp();
- shared_bitmap_manager_.reset(new SharedBitmapManagerAllocationCounter());
+ layer_tree_frame_sink_software_ = FakeLayerTreeFrameSink::CreateSoftware();
resource_provider3d_ =
FakeResourceProvider::CreateLayerTreeResourceProvider(
- context_provider_.get(), shared_bitmap_manager_.get(), nullptr,
- high_bit_for_testing_);
+ context_provider_.get(), nullptr, nullptr, high_bit_for_testing_);
resource_provider_software_ =
FakeResourceProvider::CreateLayerTreeResourceProvider(
- nullptr, shared_bitmap_manager_.get(), nullptr,
- high_bit_for_testing_);
+ nullptr, nullptr, nullptr, high_bit_for_testing_);
+ }
+
+ 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);
+ }
+
+ 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);
}
scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() {
@@ -245,7 +242,7 @@ class VideoResourceUpdaterTest : public testing::Test {
WebGraphicsContext3DUploadCounter* context3d_;
scoped_refptr<viz::TestContextProvider> context_provider_;
- std::unique_ptr<SharedBitmapManagerAllocationCounter> shared_bitmap_manager_;
+ 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_;
@@ -258,27 +255,21 @@ const gpu::SyncToken VideoResourceUpdaterTest::kMailboxSyncToken =
7);
TEST_F(VideoResourceUpdaterTest, SoftwareFrame) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
}
TEST_F(VideoResourceUpdaterTest, HighBitFrameNoF16) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
}
class VideoResourceUpdaterTestWithF16 : public VideoResourceUpdaterTest {
@@ -289,23 +280,20 @@ class VideoResourceUpdaterTestWithF16 : public VideoResourceUpdaterTest {
};
TEST_F(VideoResourceUpdaterTestWithF16, HighBitFrame) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ 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(VideoFrameExternalResources::YUV_RESOURCE, resources2.type);
+ 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);
}
@@ -319,16 +307,12 @@ class VideoResourceUpdaterTestWithR16 : public VideoResourceUpdaterTest {
};
TEST_F(VideoResourceUpdaterTestWithR16, HighBitFrame) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
- updater.SetUseR16ForTesting(true);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ 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;
@@ -338,62 +322,51 @@ TEST_F(VideoResourceUpdaterTestWithR16, HighBitFrame) {
// Create the resource again, to test the path where the
// resources are cached.
VideoFrameExternalResources resources2 =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources2.type);
+ 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) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
}
TEST_F(VideoResourceUpdaterTest, WonkySoftwareFrame) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
scoped_refptr<media::VideoFrame> video_frame = CreateWonkyTestYUVVideoFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
}
TEST_F(VideoResourceUpdaterTest, WonkySoftwareFrameSoftwareCompositor) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
scoped_refptr<media::VideoFrame> video_frame = CreateWonkyTestYUVVideoFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
}
TEST_F(VideoResourceUpdaterTest, ReuseResource) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ 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.
context3d_->ResetUploadCount();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
EXPECT_EQ(3u, resources.resources.size());
EXPECT_EQ(3u, resources.release_callbacks.size());
- EXPECT_EQ(viz::kInvalidResourceId, resources.software_resource);
// Expect exactly three texture uploads, one for each plane.
EXPECT_EQ(3, context3d_->UploadCount());
@@ -404,8 +377,8 @@ TEST_F(VideoResourceUpdaterTest, ReuseResource) {
// Allocate resources for the same frame.
context3d_->ResetUploadCount();
- resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ 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.
@@ -413,28 +386,24 @@ TEST_F(VideoResourceUpdaterTest, ReuseResource) {
}
TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDelete) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ 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.
context3d_->ResetUploadCount();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
EXPECT_EQ(3u, resources.resources.size());
EXPECT_EQ(3u, resources.release_callbacks.size());
- EXPECT_EQ(viz::kInvalidResourceId, resources.software_resource);
// Expect exactly three texture uploads, one for each plane.
EXPECT_EQ(3, context3d_->UploadCount());
// Allocate resources for the same frame.
context3d_->ResetUploadCount();
- resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ 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.
@@ -442,103 +411,87 @@ TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDelete) {
}
TEST_F(VideoResourceUpdaterTest, SoftwareFrameSoftwareCompositor) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
}
TEST_F(VideoResourceUpdaterTest, ReuseResourceSoftwareCompositor) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
- use_stream_video_draw_quad);
+ 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.
- shared_bitmap_manager_->ResetAllocationCount();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
- EXPECT_EQ(0u, resources.resources.size());
- EXPECT_EQ(0u, resources.release_callbacks.size());
- EXPECT_LT(viz::kInvalidResourceId, resources.software_resource);
+ 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(1, shared_bitmap_manager_->AllocationCount());
+ 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.software_release_callback).Run(gpu::SyncToken(), false);
+ std::move(resources.release_callbacks[0]).Run(gpu::SyncToken(), false);
// Allocate resources for the same frame.
- shared_bitmap_manager_->ResetAllocationCount();
- resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
- EXPECT_EQ(0u, resources.resources.size());
- EXPECT_EQ(0u, resources.release_callbacks.size());
- EXPECT_LT(viz::kInvalidResourceId, resources.software_resource);
- // The data should be reused so expect no new allocations.
- EXPECT_EQ(0, shared_bitmap_manager_->AllocationCount());
+ 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) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
- use_stream_video_draw_quad);
+ 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.
- shared_bitmap_manager_->ResetAllocationCount();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
- EXPECT_EQ(0u, resources.resources.size());
- EXPECT_EQ(0u, resources.release_callbacks.size());
- EXPECT_LT(viz::kInvalidResourceId, resources.software_resource);
+ 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(1, shared_bitmap_manager_->AllocationCount());
+ 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.
- shared_bitmap_manager_->ResetAllocationCount();
- resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
- EXPECT_EQ(0u, resources.resources.size());
- EXPECT_EQ(0u, resources.release_callbacks.size());
- EXPECT_NE(viz::kInvalidResourceId, resources.software_resource);
- // The data should be reused so expect no new allocations.
- EXPECT_EQ(0, shared_bitmap_manager_->AllocationCount());
+ 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, CreateForHardwarePlanes) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
scoped_refptr<media::VideoFrame> video_frame =
CreateTestRGBAHardwareVideoFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
- resources.type);
+ 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_EQ(viz::kInvalidResourceId, resources.software_resource);
video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_I420, 3,
GL_TEXTURE_RECTANGLE_ARB);
- resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ 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_EQ(viz::kInvalidResourceId, resources.software_resource);
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);
@@ -548,74 +501,62 @@ TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes) {
video_frame->metadata()->SetBoolean(
media::VideoFrameMetadata::READ_LOCK_FENCES_ENABLED, true);
- resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ 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) {
- bool use_stream_video_draw_quad = true;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ // Note that |use_stream_video_draw_quad| is true for this test.
+ std::unique_ptr<VideoResourceUpdater> updater =
+ CreateUpdaterForHardware(true);
context3d_->ResetTextureCreationCount();
scoped_refptr<media::VideoFrame> video_frame =
CreateTestStreamTextureHardwareVideoFrame(false);
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE,
- resources.type);
+ 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(viz::kInvalidResourceId, resources.software_resource);
EXPECT_EQ(0, context3d_->TextureCreationCount());
// A copied stream texture should return an RGBA resource in a new
// GL_TEXTURE_2D texture.
context3d_->ResetTextureCreationCount();
video_frame = CreateTestStreamTextureHardwareVideoFrame(true);
- resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
- resources.type);
+ 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(viz::kInvalidResourceId, resources.software_resource);
EXPECT_EQ(1, context3d_->TextureCreationCount());
}
TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_TextureQuad) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
context3d_->ResetTextureCreationCount();
scoped_refptr<media::VideoFrame> video_frame =
CreateTestStreamTextureHardwareVideoFrame(false);
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
- resources.type);
+ 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(viz::kInvalidResourceId, resources.software_resource);
EXPECT_EQ(0, context3d_->TextureCreationCount());
}
// Passthrough the sync token returned by the compositor if we don't have an
// existing release sync token.
TEST_F(VideoResourceUpdaterTest, PassReleaseSyncToken) {
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- false /* use_stream_video_draw_quad */);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
const gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
gpu::CommandBufferId::FromUnsafeValue(0x123),
@@ -626,7 +567,7 @@ TEST_F(VideoResourceUpdaterTest, PassReleaseSyncToken) {
CreateTestRGBAHardwareVideoFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
ASSERT_EQ(resources.release_callbacks.size(), 1u);
std::move(resources.release_callbacks[0]).Run(sync_token, false);
@@ -637,9 +578,7 @@ TEST_F(VideoResourceUpdaterTest, PassReleaseSyncToken) {
// Generate new sync token because video frame has an existing sync token.
TEST_F(VideoResourceUpdaterTest, GenerateReleaseSyncToken) {
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- false /* use_stream_video_draw_quad */);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
const gpu::SyncToken sync_token1(gpu::CommandBufferNamespace::GPU_IO,
gpu::CommandBufferId::FromUnsafeValue(0x123),
@@ -654,12 +593,12 @@ TEST_F(VideoResourceUpdaterTest, GenerateReleaseSyncToken) {
CreateTestRGBAHardwareVideoFrame();
VideoFrameExternalResources resources1 =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ 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);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
ASSERT_EQ(resources2.release_callbacks.size(), 1u);
std::move(resources2.release_callbacks[0]).Run(sync_token2, false);
}
@@ -672,15 +611,13 @@ TEST_F(VideoResourceUpdaterTest, GenerateReleaseSyncToken) {
// 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) {
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- false /* use_stream_video_draw_quad */);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
scoped_refptr<media::VideoFrame> video_frame =
CreateTestRGBAHardwareVideoFrame();
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
ASSERT_EQ(resources.resources.size(), 1u);
EXPECT_TRUE(resources.resources[0].mailbox_holder.sync_token.HasData());
@@ -690,15 +627,13 @@ TEST_F(VideoResourceUpdaterTest, PassMailboxSyncToken) {
// Generate new sync token for compositor when copying the texture.
TEST_F(VideoResourceUpdaterTest, GenerateSyncTokenOnTextureCopy) {
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- false /* use_stream_video_draw_quad */);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
scoped_refptr<media::VideoFrame> video_frame =
CreateTestStreamTextureHardwareVideoFrame(true /* needs_copy */);
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ updater->CreateExternalResourcesFromVideoFrame(video_frame);
ASSERT_EQ(resources.resources.size(), 1u);
EXPECT_TRUE(resources.resources[0].mailbox_holder.sync_token.HasData());
@@ -710,17 +645,14 @@ TEST_F(VideoResourceUpdaterTest, GenerateSyncTokenOnTextureCopy) {
// 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) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
context3d_->ResetTextureCreationCount();
scoped_refptr<media::VideoFrame> video_frame = CreateTestHardwareVideoFrame(
media::PIXEL_FORMAT_NV12, GL_TEXTURE_EXTERNAL_OES);
VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::RGB_RESOURCE, resources.type);
+ 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);
@@ -729,8 +661,8 @@ TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_SingleNV12) {
video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_NV12, 1,
GL_TEXTURE_RECTANGLE_ARB);
- resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::RGB_RESOURCE, resources.type);
+ 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);
@@ -741,21 +673,17 @@ TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_SingleNV12) {
}
TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_DualNV12) {
- bool use_stream_video_draw_quad = false;
- VideoResourceUpdater updater(context_provider_.get(),
- resource_provider3d_.get(),
- use_stream_video_draw_quad);
+ std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
context3d_->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(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ 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(viz::kInvalidResourceId, resources.software_resource);
EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
resources.resources[0].mailbox_holder.texture_target);
// |updater| doesn't set |buffer_format| in this case.
@@ -763,8 +691,8 @@ TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_DualNV12) {
video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_NV12, 2,
GL_TEXTURE_RECTANGLE_ARB);
- resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ 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);
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index 343dd089106..352c8649bc6 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -8,7 +8,6 @@
#include "base/auto_reset.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc
index 429f21b4d74..8f5409fc010 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine.cc
@@ -913,11 +913,6 @@ void SchedulerStateMachine::WillInvalidateLayerTreeFrameSink() {
did_invalidate_layer_tree_frame_sink_ = true;
last_frame_number_invalidate_layer_tree_frame_sink_performed_ =
current_frame_number_;
-
- // The synchronous compositor makes no guarantees about a draw coming in after
- // an invalidate so clear any flags that would cause the compositor's pipeline
- // to stall.
- active_tree_needs_first_draw_ = false; // blocks commit if true
}
void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency(
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc
index 22c8968a58c..a4e1fddba04 100644
--- a/chromium/cc/scheduler/scheduler_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_unittest.cc
@@ -3069,49 +3069,6 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
client_->Reset();
}
-TEST_F(SchedulerTest, SynchronousCompositorDoubleCommitWithoutDraw) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
-
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
-
- // Next vsync.
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
-
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
- EXPECT_NO_ACTION();
-
- scheduler_->NotifyReadyToCommit();
- EXPECT_ACTIONS("ScheduledActionCommit");
- client_->Reset();
-
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- client_->Reset();
-
- // Ask for another commit.
- scheduler_->SetNeedsBeginMainFrame();
-
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
-
- scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks());
- EXPECT_NO_ACTION();
-
- // Allow new commit even though previous commit hasn't been drawn.
- scheduler_->NotifyReadyToCommit();
- EXPECT_ACTIONS("ScheduledActionCommit");
- client_->Reset();
-}
-
class SchedulerClientSetNeedsPrepareTilesOnDraw : public FakeSchedulerClient {
public:
SchedulerClientSetNeedsPrepareTilesOnDraw() : FakeSchedulerClient() {}
diff --git a/chromium/cc/tiles/checker_image_tracker.cc b/chromium/cc/tiles/checker_image_tracker.cc
index 012cbb65efe..060eb020d1c 100644
--- a/chromium/cc/tiles/checker_image_tracker.cc
+++ b/chromium/cc/tiles/checker_image_tracker.cc
@@ -5,7 +5,6 @@
#include "cc/tiles/checker_image_tracker.h"
#include "base/bind.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
diff --git a/chromium/cc/tiles/checker_image_tracker_unittest.cc b/chromium/cc/tiles/checker_image_tracker_unittest.cc
index 0c46a4b6d5d..0b4606f1463 100644
--- a/chromium/cc/tiles/checker_image_tracker_unittest.cc
+++ b/chromium/cc/tiles/checker_image_tracker_unittest.cc
@@ -5,7 +5,6 @@
#include "cc/tiles/checker_image_tracker.h"
#include "base/bind.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/paint/paint_image_builder.h"
diff --git a/chromium/cc/tiles/eviction_tile_priority_queue.cc b/chromium/cc/tiles/eviction_tile_priority_queue.cc
index 4bb198a2876..c09fc82961c 100644
--- a/chromium/cc/tiles/eviction_tile_priority_queue.cc
+++ b/chromium/cc/tiles/eviction_tile_priority_queue.cc
@@ -4,7 +4,6 @@
#include "cc/tiles/eviction_tile_priority_queue.h"
-#include "base/memory/ptr_util.h"
namespace cc {
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc
index 97b242c908d..344515342af 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache.cc
@@ -11,7 +11,6 @@
#include "base/hash.h"
#include "base/memory/discardable_memory_allocator.h"
#include "base/memory/memory_coordinator_client_registry.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_math.h"
#include "base/strings/stringprintf.h"
@@ -211,12 +210,16 @@ sk_sp<SkImage> TakeOwnershipOfSkImageBacking(GrContext* context,
GrSurfaceOrigin origin;
image->getTextureHandle(false /* flushPendingGrContextIO */, &origin);
+ SkColorType color_type = image->colorType();
+ if (color_type == kUnknown_SkColorType) {
+ return nullptr;
+ }
sk_sp<SkColorSpace> color_space = image->refColorSpace();
GrBackendTexture backend_texture;
SkImage::BackendTextureReleaseProc release_proc;
SkImage::MakeBackendTextureFromSkImage(context, std::move(image),
&backend_texture, &release_proc);
- return SkImage::MakeFromTexture(context, backend_texture, origin,
+ return SkImage::MakeFromTexture(context, backend_texture, origin, color_type,
kPremul_SkAlphaType, std::move(color_space));
}
@@ -577,22 +580,14 @@ void GpuImageDecodeCache::ImageData::ValidateBudgeted() const {
GpuImageDecodeCache::GpuImageDecodeCache(viz::RasterContextProvider* context,
bool use_transfer_cache,
SkColorType color_type,
- size_t max_working_set_bytes)
+ size_t max_working_set_bytes,
+ int max_texture_size)
: color_type_(color_type),
use_transfer_cache_(use_transfer_cache),
context_(context),
+ max_texture_size_(max_texture_size),
persistent_cache_(PersistentCache::NO_AUTO_EVICT),
max_working_set_bytes_(max_working_set_bytes) {
- // Acquire the context_lock so that we can safely retrieve
- // |max_texture_size_|.
- {
- base::Optional<viz::RasterContextProvider::ScopedRasterContextLock>
- context_lock;
- if (context_->GetLock())
- context_lock.emplace(context_);
- max_texture_size_ = context_->GrContext()->caps()->maxTextureSize();
- }
-
// In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
// Don't register a dump provider in these cases.
if (base::ThreadTaskRunnerHandle::IsSet()) {
@@ -1351,9 +1346,9 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
image_info.minRowBytes());
// Set |pixmap| to the desired colorspace to decode into.
- if (image_data->mode == DecodedDataMode::kCpu) {
- // If this is a kCpu image, we want to handle color conversion during
- // decode, so set the target colorspace here.
+ if (!SupportsColorSpaceConversion()) {
+ pixmap.setColorSpace(nullptr);
+ } else if (image_data->mode == DecodedDataMode::kCpu) {
pixmap.setColorSpace(draw_image.target_color_space().ToSkColorSpace());
} else {
// For kGpu or kTransferCache images color conversion is handled during
@@ -1420,7 +1415,11 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
if (!image_data->decode.image()->peekPixels(&pixmap))
return;
- ClientImageTransferCacheEntry image_entry(&pixmap, nullptr);
+ sk_sp<SkColorSpace> color_space =
+ SupportsColorSpaceConversion()
+ ? draw_image.target_color_space().ToSkColorSpace()
+ : nullptr;
+ ClientImageTransferCacheEntry image_entry(&pixmap, color_space.get());
size_t size = image_entry.SerializedSize();
void* data = context_->ContextSupport()->MapTransferCacheEntry(size);
// TODO(piman): handle error (failed to allocate/map shm)
@@ -1445,11 +1444,12 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
// For kGpu, we upload and color convert (if necessary).
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 && SupportsColorSpaces() &&
+ 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;
@@ -1571,11 +1571,6 @@ void GpuImageDecodeCache::RunPendingContextThreadOperations() {
context_->ContextGL()->UnlockDiscardableTextureCHROMIUM(
GlIdFromSkImage(image));
}
- if (images_pending_unlock_.size() > 0) {
- // When we unlock images, we remove any outstanding texture bindings. We
- // need to inform Skia so it will re-generate these bindings if needed.
- context_->GrContext()->resetContext(kTextureBinding_GrGLBackendState);
- }
images_pending_unlock_.clear();
for (auto id : ids_pending_unlock_) {
@@ -1763,7 +1758,7 @@ void GpuImageDecodeCache::OnPurgeMemory() {
EnsureCapacity(0);
}
-bool GpuImageDecodeCache::SupportsColorSpaces() const {
+bool GpuImageDecodeCache::SupportsColorSpaceConversion() const {
switch (color_type_) {
case kRGBA_8888_SkColorType:
case kBGRA_8888_SkColorType:
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h
index 9a32552c96b..ea4fe73dce9 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.h
+++ b/chromium/cc/tiles/gpu_image_decode_cache.h
@@ -105,7 +105,8 @@ class CC_EXPORT GpuImageDecodeCache
explicit GpuImageDecodeCache(viz::RasterContextProvider* context,
bool use_transfer_cache,
SkColorType color_type,
- size_t max_working_set_bytes);
+ size_t max_working_set_bytes,
+ int max_texture_size);
~GpuImageDecodeCache() override;
// ImageDecodeCache overrides.
@@ -144,6 +145,8 @@ class CC_EXPORT GpuImageDecodeCache
DecodeTaskType task_type);
void OnImageUploadTaskCompleted(const DrawImage& image);
+ bool SupportsColorSpaceConversion() const;
+
// For testing only.
void SetWorkingSetLimitForTesting(size_t limit) {
max_working_set_bytes_ = limit;
@@ -420,8 +423,6 @@ class CC_EXPORT GpuImageDecodeCache
// These including deleting, unlocking, and locking textures.
void RunPendingContextThreadOperations();
- bool SupportsColorSpaces() const;
-
void CheckContextLockAcquiredIfNecessary();
const SkColorType color_type_;
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
index 52395c497c0..2c272ededad 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -19,6 +19,7 @@
#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/GrContext.h"
namespace cc {
namespace {
@@ -253,15 +254,17 @@ class GpuImageDecodeCacheTest
viz::RasterContextProvider::ScopedRasterContextLock context_lock(
context_provider_.get());
transfer_cache_helper_.SetGrContext(context_provider_->GrContext());
+ max_texture_size_ =
+ context_provider_->ContextCapabilities().max_texture_size;
}
use_transfer_cache_ = GetParam().second;
color_type_ = GetParam().first;
}
std::unique_ptr<GpuImageDecodeCache> CreateCache() {
- return base::WrapUnique(
- new GpuImageDecodeCache(context_provider_.get(), use_transfer_cache_,
- color_type_, kGpuMemoryLimitBytes));
+ return std::make_unique<GpuImageDecodeCache>(
+ context_provider_.get(), use_transfer_cache_, color_type_,
+ kGpuMemoryLimitBytes, max_texture_size_);
}
GPUImageDecodeTestMockContextProvider* context_provider() {
@@ -299,12 +302,23 @@ class GpuImageDecodeCacheTest
return draw_image;
}
- private:
+ sk_sp<SkImage> GetLastTransferredImage() {
+ auto& key = transfer_cache_helper_.GetLastAddedEntry();
+ ServiceTransferCacheEntry* entry =
+ transfer_cache_helper_.GetEntryInternal(key.first, key.second);
+ if (!entry)
+ return nullptr;
+ CHECK_EQ(TransferCacheEntryType::kImage, entry->Type());
+ return static_cast<ServiceImageTransferCacheEntry*>(entry)->image();
+ }
+
+ protected:
FakeDiscardableManager discardable_manager_;
scoped_refptr<GPUImageDecodeTestMockContextProvider> context_provider_;
TransferCacheTestHelper transfer_cache_helper_;
bool use_transfer_cache_;
SkColorType color_type_;
+ int max_texture_size_ = 0;
};
SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
@@ -2198,13 +2212,81 @@ TEST_P(GpuImageDecodeCacheTest,
DecodedDrawImage decoded_draw_image =
cache->GetDecodedImageForDraw(draw_image);
- sk_sp<SkImage> decoded_image = cache->GetSWImageDecodeForTesting(draw_image);
- // Ensure that the "uploaded" image we get back is the same as the decoded
- // image we've cached.
- ExpectIfNotUsingTransferCache(decoded_image == decoded_draw_image.image());
- // Ensure that the SW decoded image had colorspace conversion applied.
- ExpectIfNotUsingTransferCache(decoded_image->colorSpace() ==
- color_space.ToSkColorSpace().get());
+ sk_sp<SkColorSpace> target_color_space = cache->SupportsColorSpaceConversion()
+ ? color_space.ToSkColorSpace()
+ : nullptr;
+
+ if (use_transfer_cache_) {
+ // If using the transfer cache, the color conversion should be applied
+ // there as well, even if it is a software image.
+ sk_sp<SkImage> service_image = GetLastTransferredImage();
+ ASSERT_TRUE(image);
+ EXPECT_FALSE(service_image->isTextureBacked());
+ EXPECT_EQ(image.width(), service_image->width());
+ EXPECT_EQ(image.height(), service_image->height());
+
+ // Color space should be logically equal to the original color space.
+ EXPECT_TRUE(SkColorSpace::Equals(service_image->colorSpace(),
+ target_color_space.get()));
+ } else {
+ sk_sp<SkImage> decoded_image =
+ cache->GetSWImageDecodeForTesting(draw_image);
+ // Ensure that the "uploaded" image we get back is the same as the decoded
+ // image we've cached.
+ EXPECT_TRUE(decoded_image == decoded_draw_image.image());
+ // Ensure that the SW decoded image had colorspace conversion applied.
+ EXPECT_TRUE(decoded_image->colorSpace() == target_color_space.get());
+ }
+
+ cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheTest,
+ ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) {
+ auto cache = CreateCache();
+ bool is_decomposable = true;
+ SkFilterQuality quality = kHigh_SkFilterQuality;
+ gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65();
+
+ PaintImage image = CreateDiscardablePaintImage(gfx::Size(11, 12));
+ DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+ quality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ PaintImage::kDefaultFrameIndex, color_space);
+ 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());
+
+ viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+ DecodedDrawImage decoded_draw_image =
+ cache->GetDecodedImageForDraw(draw_image);
+
+ sk_sp<SkColorSpace> target_color_space = cache->SupportsColorSpaceConversion()
+ ? color_space.ToSkColorSpace()
+ : nullptr;
+
+ if (use_transfer_cache_) {
+ // If using the transfer cache, the color conversion should be applied
+ // there during upload.
+ sk_sp<SkImage> service_image = GetLastTransferredImage();
+ ASSERT_TRUE(image);
+ EXPECT_TRUE(service_image->isTextureBacked());
+ EXPECT_EQ(image.width(), service_image->width());
+ EXPECT_EQ(image.height(), service_image->height());
+
+ // Color space should be logically equal to the original color space.
+ EXPECT_TRUE(SkColorSpace::Equals(service_image->colorSpace(),
+ target_color_space.get()));
+ } else {
+ // Ensure that the HW uploaded image had color space conversion applied.
+ EXPECT_TRUE(decoded_draw_image.image()->colorSpace() ==
+ target_color_space.get());
+ }
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
cache->UnrefImage(draw_image);
diff --git a/chromium/cc/tiles/picture_layer_tiling.cc b/chromium/cc/tiles/picture_layer_tiling.cc
index 6fb4812e47c..4901cdbfa38 100644
--- a/chromium/cc/tiles/picture_layer_tiling.cc
+++ b/chromium/cc/tiles/picture_layer_tiling.cc
@@ -13,7 +13,6 @@
#include "base/containers/flat_map.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
diff --git a/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
index 7ea10ee38bc..278f97b6f4b 100644
--- a/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
+++ b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
@@ -7,7 +7,6 @@
#include <map>
#include <vector>
-#include "base/memory/ptr_util.h"
#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/resources/resource_provider.h"
#include "cc/test/fake_output_surface_client.h"
diff --git a/chromium/cc/tiles/raster_tile_priority_queue_all.cc b/chromium/cc/tiles/raster_tile_priority_queue_all.cc
index 96b98c5aa65..564ddfef40b 100644
--- a/chromium/cc/tiles/raster_tile_priority_queue_all.cc
+++ b/chromium/cc/tiles/raster_tile_priority_queue_all.cc
@@ -4,7 +4,6 @@
#include "cc/tiles/raster_tile_priority_queue_all.h"
-#include "base/memory/ptr_util.h"
#include "cc/tiles/tiling_set_raster_queue_all.h"
namespace cc {
diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc
index c47c6894133..e566d3a1e1b 100644
--- a/chromium/cc/tiles/software_image_decode_cache.cc
+++ b/chromium/cc/tiles/software_image_decode_cache.cc
@@ -24,6 +24,24 @@ 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.
// Depending on the memory state of the system, we limit the amount of items
@@ -206,10 +224,7 @@ SoftwareImageDecodeCache::GetTaskForImageAndRefInternal(
if (key.target_size().IsEmpty())
return TaskResult(false);
- // For non-lazy images a decode isn't necessary.
- // TODO(khushalsagar): If these images require color conversion, we should
- // still cache that result.
- if (!image.paint_image().IsLazyGenerated())
+ if (!UseCacheForDrawImage(image))
return TaskResult(false);
base::AutoLock lock(lock_);
@@ -475,8 +490,8 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary(
DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDraw(
const DrawImage& draw_image) {
- // Non-lazy generated images can be used for raster directly.
- if (!draw_image.paint_image().GetSkImage()->isLazyGenerated()) {
+ // 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(),
@@ -523,8 +538,7 @@ DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDrawInternal(
void SoftwareImageDecodeCache::DrawWithImageFinished(
const DrawImage& image,
const DecodedDrawImage& decoded_image) {
- // We don't cache any data for non-lazy images.
- if (!image.paint_image().IsLazyGenerated())
+ if (!UseCacheForDrawImage(image))
return;
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
diff --git a/chromium/cc/tiles/tile.cc b/chromium/cc/tiles/tile.cc
index 1dd63678395..db0ba9f0177 100644
--- a/chromium/cc/tiles/tile.cc
+++ b/chromium/cc/tiles/tile.cc
@@ -12,8 +12,8 @@
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/base/math_util.h"
-#include "cc/resources/resource_util.h"
#include "cc/tiles/tile_manager.h"
+#include "components/viz/common/resources/resource_sizes.h"
#include "components/viz/common/traced_value.h"
namespace cc {
@@ -81,7 +81,7 @@ size_t Tile::GPUMemoryUsageInBytes() const {
if (draw_info_.resource_) {
// We can use UncheckedSizeInBytes, since the tile size is determined by the
// compositor.
- return ResourceUtil::UncheckedSizeInBytes<size_t>(
+ return viz::ResourceSizes::UncheckedSizeInBytes<size_t>(
draw_info_.resource_size(), draw_info_.resource_format());
}
return 0;
diff --git a/chromium/cc/tiles/tile_draw_info.cc b/chromium/cc/tiles/tile_draw_info.cc
index 0e51c2b2402..0c09fa281d7 100644
--- a/chromium/cc/tiles/tile_draw_info.cc
+++ b/chromium/cc/tiles/tile_draw_info.cc
@@ -22,7 +22,8 @@ void TileDrawInfo::AsValueInto(base::trace_event::TracedValue* state) const {
void TileDrawInfo::SetResource(ResourcePool::InUsePoolResource resource,
bool resource_is_checker_imaged,
- bool contents_swizzled) {
+ bool contents_swizzled,
+ bool is_premultiplied) {
DCHECK(!resource_);
DCHECK(resource);
@@ -30,6 +31,7 @@ void TileDrawInfo::SetResource(ResourcePool::InUsePoolResource resource,
is_resource_ready_to_draw_ = false;
resource_is_checker_imaged_ = resource_is_checker_imaged;
contents_swizzled_ = contents_swizzled;
+ is_premultiplied_ = is_premultiplied;
resource_ = std::move(resource);
}
@@ -45,6 +47,7 @@ ResourcePool::InUsePoolResource TileDrawInfo::TakeResource() {
is_resource_ready_to_draw_ = false;
resource_is_checker_imaged_ = false;
contents_swizzled_ = false;
+ is_premultiplied_ = false;
return std::move(resource_);
}
diff --git a/chromium/cc/tiles/tile_draw_info.h b/chromium/cc/tiles/tile_draw_info.h
index 5ae3cbe0f62..c401258c103 100644
--- a/chromium/cc/tiles/tile_draw_info.h
+++ b/chromium/cc/tiles/tile_draw_info.h
@@ -73,6 +73,7 @@ class CC_EXPORT TileDrawInfo {
}
bool contents_swizzled() const { return contents_swizzled_; }
+ bool is_premultiplied() const { return is_premultiplied_; }
bool requires_resource() const {
return mode_ == RESOURCE_MODE || mode_ == OOM_MODE;
@@ -101,7 +102,8 @@ class CC_EXPORT TileDrawInfo {
void SetResource(ResourcePool::InUsePoolResource resource,
bool resource_is_checker_imaged,
- bool contents_swizzled);
+ bool contents_swizzled,
+ bool is_premultiplied);
ResourcePool::InUsePoolResource TakeResource();
void set_resource_ready_for_draw() {
@@ -120,6 +122,7 @@ class CC_EXPORT TileDrawInfo {
SkColor solid_color_ = SK_ColorWHITE;
ResourcePool::InUsePoolResource resource_;
bool contents_swizzled_ = false;
+ bool is_premultiplied_ = false;
bool is_resource_ready_to_draw_ = false;
// Set to true if |resource_| was rasterized with checker-imaged content. The
diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc
index f6234675743..33324a69a7f 100644
--- a/chromium/cc/tiles/tile_manager.cc
+++ b/chromium/cc/tiles/tile_manager.cc
@@ -15,7 +15,6 @@
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
@@ -28,9 +27,9 @@
#include "cc/raster/playback_image_provider.h"
#include "cc/raster/raster_buffer.h"
#include "cc/raster/task_category.h"
-#include "cc/resources/resource_util.h"
#include "cc/tiles/frame_viewer_instrumentation.h"
#include "cc/tiles/tile.h"
+#include "components/viz/common/resources/resource_sizes.h"
#include "ui/gfx/geometry/axis_transform2d.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -369,7 +368,7 @@ TileManager::TileManager(
base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
base::Unretained(this))),
signals_check_notifier_(task_runner_,
- base::Bind(&TileManager::CheckAndIssueSignals,
+ base::Bind(&TileManager::FlushAndIssueSignals,
base::Unretained(this))),
has_scheduled_tile_tasks_(false),
prepare_tiles_count_(0u),
@@ -415,13 +414,11 @@ void TileManager::SetResources(ResourcePool* resource_pool,
ImageDecodeCache* image_decode_cache,
TaskGraphRunner* task_graph_runner,
RasterBufferProvider* raster_buffer_provider,
- size_t scheduled_raster_task_limit,
bool use_gpu_rasterization) {
DCHECK(!tile_task_manager_);
DCHECK(task_graph_runner);
use_gpu_rasterization_ = use_gpu_rasterization;
- scheduled_raster_task_limit_ = scheduled_raster_task_limit;
resource_pool_ = resource_pool;
image_controller_.SetImageDecodeCache(image_decode_cache);
tile_task_manager_ = TileTaskManagerImpl::Create(task_graph_runner);
@@ -444,7 +441,7 @@ void TileManager::DidFinishRunningTileTasksRequiredForActivation() {
ScheduledTasksStateAsValue());
// TODO(vmpstr): Temporary check to debug crbug.com/642927.
CHECK(tile_task_manager_);
- signals_.ready_to_activate = true;
+ signals_.activate_tile_tasks_completed = true;
signals_check_notifier_.Schedule();
}
@@ -454,7 +451,7 @@ void TileManager::DidFinishRunningTileTasksRequiredForDraw() {
ScheduledTasksStateAsValue());
// TODO(vmpstr): Temporary check to debug crbug.com/642927.
CHECK(tile_task_manager_);
- signals_.ready_to_draw = true;
+ signals_.draw_tile_tasks_completed = true;
signals_check_notifier_.Schedule();
}
@@ -494,12 +491,12 @@ bool TileManager::PrepareTiles(
return false;
}
- signals_.reset();
+ signals_ = Signals();
global_state_ = state;
// Ensure that we don't schedule any decode work for checkered images until
// the raster work for visible tiles is complete. This is done in
- // CheckAndIssueSignals when the ready to activate/draw signals are dispatched
+ // FlushAndIssueSignals when the ready to activate/draw signals are dispatched
// to the client.
checker_image_tracker_.SetNoDecodesAllowed();
@@ -538,7 +535,7 @@ void TileManager::CheckForCompletedTasks() {
tile_task_manager_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
- CheckPendingGpuWorkTiles(true /* issue_signals */, false /* flush */);
+ CheckPendingGpuWorkAndIssueSignals();
TRACE_EVENT_INSTANT1(
"cc", "TileManager::CheckForCompletedTasksFinished",
@@ -885,14 +882,10 @@ void TileManager::PartitionImagesForCheckering(
WhichTree tree = tile->tiling()->tree();
for (const auto* original_draw_image : images_in_tile) {
- size_t frame_index = original_draw_image->paint_image().frame_index();
- if (tile_manager_settings_.enable_image_animations) {
- const auto& image = original_draw_image->paint_image();
- frame_index = client_->GetFrameIndexForImage(image, tree);
- if (image_to_frame_index) {
- (*image_to_frame_index)[image.stable_id()] = frame_index;
- }
- }
+ const auto& image = original_draw_image->paint_image();
+ size_t frame_index = client_->GetFrameIndexForImage(image, tree);
+ if (image_to_frame_index)
+ (*image_to_frame_index)[image.stable_id()] = frame_index;
DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(),
frame_index, raster_color_space);
@@ -915,11 +908,8 @@ void TileManager::AddCheckeredImagesToDecodeQueue(
WhichTree tree = tile->tiling()->tree();
for (const auto* original_draw_image : images_in_tile) {
- size_t frame_index = original_draw_image->paint_image().frame_index();
- if (tile_manager_settings_.enable_image_animations) {
- frame_index = client_->GetFrameIndexForImage(
- original_draw_image->paint_image(), tree);
- }
+ size_t frame_index = client_->GetFrameIndexForImage(
+ original_draw_image->paint_image(), tree);
DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(),
frame_index, raster_color_space);
if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree)) {
@@ -1221,7 +1211,7 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask(
}
void TileManager::ResetSignalsForTesting() {
- signals_.reset();
+ signals_ = Signals();
}
void TileManager::OnRasterTaskCompleted(
@@ -1279,9 +1269,11 @@ void TileManager::OnRasterTaskCompleted(
TileDrawInfo& draw_info = tile->draw_info();
bool needs_swizzle =
raster_buffer_provider_->IsResourceSwizzleRequired(!tile->is_opaque());
+ bool is_premultiplied =
+ raster_buffer_provider_->IsResourcePremultiplied(!tile->is_opaque());
draw_info.SetResource(std::move(resource),
raster_task_was_scheduled_with_checker_images,
- needs_swizzle);
+ needs_swizzle, is_premultiplied);
if (raster_task_was_scheduled_with_checker_images)
num_of_tiles_with_checker_images_++;
@@ -1359,30 +1351,34 @@ bool TileManager::IsReadyToDraw() const {
RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
}
-void TileManager::CheckAndIssueSignals() {
- TRACE_EVENT0("cc", "TileManager::CheckAndIssueSignals");
+void TileManager::FlushAndIssueSignals() {
+ TRACE_EVENT0("cc", "TileManager::FlushAndIssueSignals");
tile_task_manager_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
- CheckPendingGpuWorkTiles(false /* issue_signals */, true /* flush */);
+ raster_buffer_provider_->Flush();
+ CheckPendingGpuWorkAndIssueSignals();
+}
+void TileManager::IssueSignals() {
// Ready to activate.
- if (signals_.ready_to_activate && !signals_.did_notify_ready_to_activate) {
- signals_.ready_to_activate = false;
+ if (signals_.activate_tile_tasks_completed &&
+ signals_.activate_gpu_work_completed &&
+ !signals_.did_notify_ready_to_activate) {
if (IsReadyToActivate()) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "TileManager::CheckAndIssueSignals - ready to activate");
+ "TileManager::IssueSignals - ready to activate");
signals_.did_notify_ready_to_activate = true;
client_->NotifyReadyToActivate();
}
}
// Ready to draw.
- if (signals_.ready_to_draw && !signals_.did_notify_ready_to_draw) {
- signals_.ready_to_draw = false;
+ if (signals_.draw_tile_tasks_completed && signals_.draw_gpu_work_completed &&
+ !signals_.did_notify_ready_to_draw) {
if (IsReadyToDraw()) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "TileManager::CheckAndIssueSignals - ready to draw");
+ "TileManager::IssueSignals - ready to draw");
signals_.did_notify_ready_to_draw = true;
client_->NotifyReadyToDraw();
}
@@ -1391,11 +1387,9 @@ void TileManager::CheckAndIssueSignals() {
// All tile tasks completed.
if (signals_.all_tile_tasks_completed &&
!signals_.did_notify_all_tile_tasks_completed) {
- signals_.all_tile_tasks_completed = false;
if (!has_scheduled_tile_tasks_) {
- TRACE_EVENT0(
- TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "TileManager::CheckAndIssueSignals - all tile tasks completed");
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "TileManager::IssueSignals - all tile tasks completed");
signals_.did_notify_all_tile_tasks_completed = true;
client_->NotifyAllTileTasksCompleted();
}
@@ -1451,8 +1445,8 @@ void TileManager::CheckIfMoreTilesNeedToBePrepared() {
CHECK(tile_task_manager_);
// Schedule all checks in case we're left with solid color tiles only.
- signals_.ready_to_activate = true;
- signals_.ready_to_draw = true;
+ signals_.activate_tile_tasks_completed = true;
+ signals_.draw_tile_tasks_completed = true;
signals_.all_tile_tasks_completed = true;
signals_check_notifier_.Schedule();
@@ -1533,8 +1527,10 @@ TileManager::ScheduledTasksStateAsValue() const {
std::unique_ptr<base::trace_event::TracedValue> state(
new base::trace_event::TracedValue());
state->BeginDictionary("tasks_pending");
- state->SetBoolean("ready_to_activate", signals_.ready_to_activate);
- state->SetBoolean("ready_to_draw", signals_.ready_to_draw);
+ state->SetBoolean("activate_tile_tasks_completed",
+ signals_.activate_tile_tasks_completed);
+ state->SetBoolean("draw_tile_tasks_completed",
+ signals_.draw_tile_tasks_completed);
state->SetBoolean("all_tile_tasks_completed",
signals_.all_tile_tasks_completed);
state->EndDictionary();
@@ -1546,15 +1542,12 @@ bool TileManager::UsePartialRaster() const {
raster_buffer_provider_->CanPartialRasterIntoProvidedResource();
}
-void TileManager::CheckPendingGpuWorkTiles(bool issue_signals, bool flush) {
- TRACE_EVENT2("cc", "TileManager::CheckPendingGpuWorkTiles",
+void TileManager::CheckPendingGpuWorkAndIssueSignals() {
+ TRACE_EVENT2("cc", "TileManager::CheckPendingGpuWorkAndIssueSignals",
"pending_gpu_work_tiles", pending_gpu_work_tiles_.size(),
"tree_priority",
TreePriorityToString(global_state_.tree_priority));
- if (flush)
- raster_buffer_provider_->Flush();
-
std::vector<const ResourcePool::InUsePoolResource*> required_for_activation;
std::vector<const ResourcePool::InUsePoolResource*> required_for_draw;
@@ -1592,9 +1585,8 @@ void TileManager::CheckPendingGpuWorkTiles(bool issue_signals, bool flush) {
pending_required_for_activation_callback_id_ =
raster_buffer_provider_->SetReadyToDrawCallback(
required_for_activation,
- base::Bind(&TileManager::CheckPendingGpuWorkTiles,
- ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr(),
- true /* issue_signals */, false /* flush */),
+ base::Bind(&TileManager::CheckPendingGpuWorkAndIssueSignals,
+ ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
pending_required_for_activation_callback_id_);
}
@@ -1604,22 +1596,21 @@ void TileManager::CheckPendingGpuWorkTiles(bool issue_signals, bool flush) {
pending_required_for_draw_callback_id_ =
raster_buffer_provider_->SetReadyToDrawCallback(
required_for_draw,
- base::Bind(&TileManager::CheckPendingGpuWorkTiles,
- ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr(),
- true /* issue_signals */, false /* flush */),
+ base::Bind(&TileManager::CheckPendingGpuWorkAndIssueSignals,
+ ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
pending_required_for_draw_callback_id_);
}
// Update our signals now that we know whether we have pending resources.
- signals_.ready_to_activate =
+ signals_.activate_gpu_work_completed =
(pending_required_for_activation_callback_id_ == 0);
- signals_.ready_to_draw = (pending_required_for_draw_callback_id_ == 0);
-
- if (issue_signals && (signals_.ready_to_activate || signals_.ready_to_draw))
- signals_check_notifier_.Schedule();
+ signals_.draw_gpu_work_completed =
+ (pending_required_for_draw_callback_id_ == 0);
// We've just updated all pending tile requirements if necessary.
pending_tile_requirements_dirty_ = false;
+
+ IssueSignals();
}
// Utility function that can be used to create a "Task set finished" task that
@@ -1720,8 +1711,8 @@ TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
// We can use UncheckedSizeInBytes here since this is used with a tile
// size which is determined by the compositor (it's at most max texture
// size).
- return MemoryUsage(ResourceUtil::UncheckedSizeInBytes<size_t>(size, format),
- 1);
+ return MemoryUsage(
+ viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format), 1);
}
// static
@@ -1760,19 +1751,6 @@ bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
resource_count_ > limit.resource_count_;
}
-TileManager::Signals::Signals() {
- reset();
-}
-
-void TileManager::Signals::reset() {
- ready_to_activate = false;
- did_notify_ready_to_activate = false;
- ready_to_draw = false;
- did_notify_ready_to_draw = false;
- all_tile_tasks_completed = false;
- did_notify_all_tile_tasks_completed = false;
-}
-
TileManager::PrioritizedWorkToSchedule::PrioritizedWorkToSchedule() = default;
TileManager::PrioritizedWorkToSchedule::PrioritizedWorkToSchedule(
PrioritizedWorkToSchedule&& other) = default;
diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h
index 1c4a90d631a..32e9a1ea563 100644
--- a/chromium/cc/tiles/tile_manager.h
+++ b/chromium/cc/tiles/tile_manager.h
@@ -156,7 +156,6 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
ImageDecodeCache* image_decode_cache,
TaskGraphRunner* task_graph_runner,
RasterBufferProvider* raster_buffer_provider,
- size_t scheduled_raster_task_limit,
bool use_gpu_rasterization);
// This causes any completed raster work to finalize, so that tiles get up to
@@ -205,7 +204,7 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
gpu::GPU_IO, gpu::CommandBufferId::FromUnsafeValue(1), 1);
}
resource_pool_->PrepareForExport(resource);
- draw_info.SetResource(std::move(resource), false, false);
+ draw_info.SetResource(std::move(resource), false, false, false);
draw_info.set_resource_ready_for_draw();
}
}
@@ -313,16 +312,16 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
};
struct Signals {
- Signals();
+ bool activate_tile_tasks_completed = false;
+ bool draw_tile_tasks_completed = false;
+ bool all_tile_tasks_completed = false;
- void reset();
+ bool activate_gpu_work_completed = false;
+ bool draw_gpu_work_completed = false;
- bool ready_to_activate;
- bool did_notify_ready_to_activate;
- bool ready_to_draw;
- bool did_notify_ready_to_draw;
- bool all_tile_tasks_completed;
- bool did_notify_all_tile_tasks_completed;
+ bool did_notify_ready_to_activate = false;
+ bool did_notify_ready_to_draw = false;
+ bool did_notify_all_tile_tasks_completed = false;
};
struct PrioritizedWorkToSchedule {
@@ -359,7 +358,6 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
bool TilePriorityViolatesMemoryPolicy(const TilePriority& priority);
bool AreRequiredTilesReadyToDraw(RasterTilePriorityQueue::Type type) const;
void CheckIfMoreTilesNeedToBePrepared();
- void CheckAndIssueSignals();
void MarkTilesOutOfMemory(
std::unique_ptr<RasterTilePriorityQueue> queue) const;
@@ -392,7 +390,9 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
bool UsePartialRaster() const;
- void CheckPendingGpuWorkTiles(bool issue_signals, bool flush);
+ void FlushAndIssueSignals();
+ void CheckPendingGpuWorkAndIssueSignals();
+ void IssueSignals();
TileManagerClient* client_;
base::SequencedTaskRunner* task_runner_;
@@ -435,7 +435,7 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
uint64_t pending_required_for_activation_callback_id_ = 0;
uint64_t pending_required_for_draw_callback_id_ = 0;
// If true, we should re-compute tile requirements in
- // CheckPendingGpuWorkTiles.
+ // CheckPendingGpuWorkAndIssueSignals.
bool pending_tile_requirements_dirty_ = false;
std::unordered_map<Tile::Id, std::vector<DrawImage>> scheduled_draw_images_;
diff --git a/chromium/cc/tiles/tile_manager_perftest.cc b/chromium/cc/tiles/tile_manager_perftest.cc
index 421848a937b..6bb3562ab13 100644
--- a/chromium/cc/tiles/tile_manager_perftest.cc
+++ b/chromium/cc/tiles/tile_manager_perftest.cc
@@ -7,7 +7,6 @@
#include "base/lazy_instance.h"
#include "base/location.h"
-#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "cc/base/lap_timer.h"
diff --git a/chromium/cc/tiles/tile_manager_settings.h b/chromium/cc/tiles/tile_manager_settings.h
index 7a3d158af07..6a7f7fb1f0c 100644
--- a/chromium/cc/tiles/tile_manager_settings.h
+++ b/chromium/cc/tiles/tile_manager_settings.h
@@ -13,7 +13,6 @@ struct CC_EXPORT TileManagerSettings {
bool use_partial_raster = false;
bool enable_checker_imaging = false;
size_t min_image_bytes_to_checker = 1 * 1024 * 1024;
- bool enable_image_animations = false;
};
} // namespace cc
diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc
index e3abdb183d8..8c9a5f4f19a 100644
--- a/chromium/cc/tiles/tile_manager_unittest.cc
+++ b/chromium/cc/tiles/tile_manager_unittest.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -18,7 +17,6 @@
#include "cc/raster/raster_source.h"
#include "cc/raster/synchronous_task_graph_runner.h"
#include "cc/resources/resource_pool.h"
-#include "cc/resources/resource_util.h"
#include "cc/test/fake_impl_task_runner_provider.h"
#include "cc/test/fake_layer_tree_frame_sink.h"
#include "cc/test/fake_layer_tree_frame_sink_client.h"
@@ -40,6 +38,7 @@
#include "cc/tiles/tile_priority.h"
#include "cc/tiles/tiling_set_raster_queue_all.h"
#include "cc/trees/layer_tree_impl.h"
+#include "components/viz/common/resources/resource_sizes.h"
#include "components/viz/test/begin_frame_args_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -1370,8 +1369,9 @@ TEST_F(TileManagerTilePriorityQueueTest,
host_impl()->resource_provider()->best_texture_format());
ManagedMemoryPolicy policy = host_impl()->ActualManagedMemoryPolicy();
- policy.bytes_limit_when_visible = ResourceUtil::UncheckedSizeInBytes<size_t>(
- gfx::Size(256, 256), viz::RGBA_8888);
+ policy.bytes_limit_when_visible =
+ viz::ResourceSizes::UncheckedSizeInBytes<size_t>(gfx::Size(256, 256),
+ viz::RGBA_8888);
host_impl()->SetMemoryPolicy(policy);
EXPECT_FALSE(host_impl()->is_likely_to_require_a_draw());
@@ -1523,6 +1523,62 @@ TEST_F(TileManagerTilePriorityQueueTest, NoRasterTasksforSolidColorTiles) {
}
}
+class TestSoftwareBacking : public ResourcePool::SoftwareBacking {
+ public:
+ // No tracing is done during these tests.
+ base::UnguessableToken SharedMemoryGuid() override { return {}; }
+
+ std::unique_ptr<uint32_t[]> pixels;
+};
+
+// A RasterBufferProvider that allocates software backings with a standard
+// array as the backing. Overrides Playback() on the RasterBuffer to raster
+// into the pixels in the array.
+class TestSoftwareRasterBufferProvider : public FakeRasterBufferProviderImpl {
+ public:
+ std::unique_ptr<RasterBuffer> AcquireBufferForRaster(
+ const ResourcePool::InUsePoolResource& resource,
+ uint64_t resource_content_id,
+ uint64_t previous_content_id) override {
+ if (!resource.software_backing()) {
+ auto backing = std::make_unique<TestSoftwareBacking>();
+ backing->shared_bitmap_id = viz::SharedBitmap::GenerateId();
+ backing->pixels = std::make_unique<uint32_t[]>(
+ viz::ResourceSizes::CheckedSizeInBytes<size_t>(resource.size(),
+ viz::RGBA_8888));
+ resource.set_software_backing(std::move(backing));
+ }
+ auto* backing =
+ static_cast<TestSoftwareBacking*>(resource.software_backing());
+ return std::make_unique<TestRasterBuffer>(resource.size(),
+ backing->pixels.get());
+ }
+
+ private:
+ class TestRasterBuffer : public RasterBuffer {
+ public:
+ TestRasterBuffer(const gfx::Size& size, void* pixels)
+ : size_(size), pixels_(pixels) {}
+
+ void Playback(
+ const RasterSource* raster_source,
+ const gfx::Rect& raster_full_rect,
+ const gfx::Rect& raster_dirty_rect,
+ uint64_t new_content_id,
+ const gfx::AxisTransform2d& transform,
+ const RasterSource::PlaybackSettings& playback_settings) override {
+ RasterBufferProvider::PlaybackToMemory(
+ pixels_, viz::RGBA_8888, size_, /*stride=*/0, raster_source,
+ raster_full_rect, /*playback_rect=*/raster_full_rect, transform,
+ gfx::ColorSpace(), playback_settings);
+ }
+
+ private:
+ gfx::Size size_;
+ void* pixels_;
+ };
+};
+
class TileManagerTest : public TestLayerTreeHostBase {
public:
// MockLayerTreeHostImpl allows us to intercept tile manager callbacks.
@@ -1665,7 +1721,20 @@ TEST_F(TileManagerTest, ActivateAndDrawWhenOOM) {
}
}
-TEST_F(TileManagerTest, LowResHasNoImage) {
+class PixelInspectTileManagerTest : public TileManagerTest {
+ public:
+ void SetUp() override {
+ TileManagerTest::SetUp();
+ // Use a RasterBufferProvider that will let us inspect pixels.
+ host_impl()->tile_manager()->SetRasterBufferProviderForTesting(
+ &raster_buffer_provider_);
+ }
+
+ private:
+ TestSoftwareRasterBufferProvider raster_buffer_provider_;
+};
+
+TEST_F(PixelInspectTileManagerTest, LowResHasNoImage) {
gfx::Size size(10, 12);
TileResolution resolutions[] = {HIGH_RESOLUTION, LOW_RESOLUTION};
@@ -1731,10 +1800,10 @@ TEST_F(TileManagerTest, LowResHasNoImage) {
resource_size.height());
// CreateLayerTreeFrameSink() sets up a software compositing, so the
// tile resource will be a bitmap.
- viz::SharedBitmap* shared_bitmap =
- tile->draw_info().GetResource().shared_bitmap();
+ auto* backing = static_cast<TestSoftwareBacking*>(
+ tile->draw_info().GetResource().software_backing());
SkBitmap bitmap;
- bitmap.installPixels(info, shared_bitmap->pixels(), info.minRowBytes());
+ bitmap.installPixels(info, backing->pixels.get(), info.minRowBytes());
for (int x = 0; x < size.width(); ++x) {
for (int y = 0; y < size.height(); ++y) {
@@ -1933,9 +2002,7 @@ void RunPartialRasterCheck(std::unique_ptr<LayerTreeHostImpl> host_impl,
host_impl->resource_pool()->AcquireResource(kTileSize, viz::RGBA_8888,
gfx::ColorSpace());
- resource.set_shared_bitmap(host_impl->layer_tree_frame_sink()
- ->shared_bitmap_manager()
- ->AllocateSharedBitmap(kTileSize));
+ resource.set_software_backing(std::make_unique<TestSoftwareBacking>());
host_impl->resource_pool()->PrepareForExport(resource);
host_impl->resource_pool()->OnContentReplaced(resource, kInvalidatedId);
@@ -2106,9 +2173,8 @@ class MockReadyToDrawRasterBufferProviderImpl
const ResourcePool::InUsePoolResource& resource,
uint64_t resource_content_id,
uint64_t previous_content_id) override {
- if (!resource.shared_bitmap())
- resource.set_shared_bitmap(
- shared_bitmap_manager_.AllocateSharedBitmap(resource.size()));
+ if (!resource.software_backing())
+ resource.set_software_backing(std::make_unique<TestSoftwareBacking>());
return std::make_unique<FakeRasterBuffer>();
}
@@ -2123,8 +2189,6 @@ class MockReadyToDrawRasterBufferProviderImpl
const gfx::AxisTransform2d& transform,
const RasterSource::PlaybackSettings& playback_settings) override {}
};
-
- viz::TestSharedBitmapManager shared_bitmap_manager_;
};
class TileManagerReadyToDrawTest : public TileManagerTest {
diff --git a/chromium/cc/trees/clip_node.cc b/chromium/cc/trees/clip_node.cc
index 3c9c58fcece..c1a73a952c5 100644
--- a/chromium/cc/trees/clip_node.cc
+++ b/chromium/cc/trees/clip_node.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/base/math_util.h"
#include "cc/layers/layer.h"
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
index bfddc4c0eb6..d3c1958a13c 100644
--- a/chromium/cc/trees/draw_property_utils.cc
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -677,6 +677,11 @@ static gfx::Rect LayerVisibleRect(PropertyTrees* property_trees,
bool non_root_copy_request_or_cache_render_surface =
lower_effect_closest_ancestor > EffectTree::kContentsRootNodeId;
gfx::Rect layer_content_rect = gfx::Rect(layer->bounds());
+ if (layer->layer_tree_impl()->IsRootLayer(layer) &&
+ !layer->layer_tree_impl()->viewport_visible_rect().IsEmpty()) {
+ layer_content_rect.Intersect(
+ layer->layer_tree_impl()->viewport_visible_rect());
+ }
gfx::RectF accumulated_clip_in_root_space;
if (non_root_copy_request_or_cache_render_surface) {
bool include_expanding_clips = true;
diff --git a/chromium/cc/trees/frame_token_allocator.cc b/chromium/cc/trees/frame_token_allocator.cc
new file mode 100644
index 00000000000..4f6ec1cf91c
--- /dev/null
+++ b/chromium/cc/trees/frame_token_allocator.cc
@@ -0,0 +1,26 @@
+// 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
new file mode 100644
index 00000000000..1bb978d631f
--- /dev/null
+++ b/chromium/cc/trees/frame_token_allocator.h
@@ -0,0 +1,52 @@
+// 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/image_animation_controller.cc b/chromium/cc/trees/image_animation_controller.cc
index 1a19cbc06ac..a781c08f8cd 100644
--- a/chromium/cc/trees/image_animation_controller.cc
+++ b/chromium/cc/trees/image_animation_controller.cc
@@ -21,8 +21,10 @@ const base::TimeDelta kAnimationResyncCutoff = base::TimeDelta::FromMinutes(5);
ImageAnimationController::ImageAnimationController(
base::SingleThreadTaskRunner* task_runner,
- base::Closure invalidation_callback)
- : notifier_(task_runner, invalidation_callback) {}
+ base::RepeatingClosure invalidation_callback,
+ bool enable_image_animation_resync)
+ : notifier_(task_runner, invalidation_callback),
+ enable_image_animation_resync_(enable_image_animation_resync) {}
ImageAnimationController::~ImageAnimationController() = default;
@@ -71,7 +73,7 @@ const PaintImageIdFlatSet& ImageAnimationController::AnimateForSyncTree(
// If we were able to advance this animation, invalidate it on the sync
// tree.
- if (state.AdvanceFrame(now))
+ if (state.AdvanceFrame(now, enable_image_animation_resync_))
images_animated_on_sync_tree_.insert(id);
// Update the next invalidation time to the earliest time at which we need
@@ -137,8 +139,21 @@ void ImageAnimationController::DidActivate() {
DCHECK(it != animation_state_map_.end());
it->second.PushPendingToActive();
}
-
images_animated_on_sync_tree_.clear();
+
+ // We would retain state for images with no drivers (no recordings) to allow
+ // resuming of animations. However, since the animation will be re-started
+ // from the beginning after navigation, we can avoid maintaining the state.
+ if (did_navigate_) {
+ for (auto it = animation_state_map_.begin();
+ it != animation_state_map_.end();) {
+ if (it->second.has_drivers())
+ it++;
+ else
+ it = animation_state_map_.erase(it);
+ }
+ did_navigate_ = false;
+ }
}
size_t ImageAnimationController::GetFrameIndexForImage(
@@ -216,7 +231,8 @@ bool ImageAnimationController::AnimationState::ShouldAnimate() const {
}
bool ImageAnimationController::AnimationState::AdvanceFrame(
- base::TimeTicks now) {
+ base::TimeTicks now,
+ bool enable_image_animation_resync) {
DCHECK(ShouldAnimate());
// Start the animation from the first frame, if not yet started. We don't need
@@ -240,7 +256,8 @@ bool ImageAnimationController::AnimationState::AdvanceFrame(
// up and start again from the current frame.
// Note that we don't need to invalidate this image since the active tree
// is already displaying the current frame.
- if (now - next_desired_frame_time_ > kAnimationResyncCutoff) {
+ if (enable_image_animation_resync &&
+ now - next_desired_frame_time_ > kAnimationResyncCutoff) {
DCHECK_EQ(pending_index_, active_index_);
next_desired_frame_time_ = now + frames_[pending_index_].duration;
return false;
@@ -268,8 +285,8 @@ bool ImageAnimationController::AnimationState::AdvanceFrame(
// pages that try to sync an image and some other resource (e.g. audio),
// especially if users switch tabs (and thus stop drawing the animation,
// which will pause it) during that initial loop, then switch back later.
- if (next_frame_index == 0u && repetitions_completed_ == 1 &&
- next_desired_frame_time <= now) {
+ if (enable_image_animation_resync && next_frame_index == 0u &&
+ repetitions_completed_ == 1 && next_desired_frame_time <= now) {
pending_index_ = 0u;
next_desired_frame_time_ = now + frames_[0].duration;
repetitions_completed_ = 0;
@@ -369,7 +386,7 @@ size_t ImageAnimationController::AnimationState::NextFrameIndex() const {
ImageAnimationController::DelayedNotifier::DelayedNotifier(
base::SingleThreadTaskRunner* task_runner,
- base::Closure closure)
+ base::RepeatingClosure closure)
: task_runner_(task_runner),
closure_(std::move(closure)),
weak_factory_(this) {
diff --git a/chromium/cc/trees/image_animation_controller.h b/chromium/cc/trees/image_animation_controller.h
index 13a85bbc206..ec73e0419a1 100644
--- a/chromium/cc/trees/image_animation_controller.h
+++ b/chromium/cc/trees/image_animation_controller.h
@@ -58,8 +58,11 @@ class CC_EXPORT ImageAnimationController {
// created.
// |task_runner| is the thread on which the controller is used. The
// invalidation_callback can only be run on this thread.
+ // |enable_image_animation_resync| specifies whether the animation can be
+ // reset to the beginning to avoid skipping many frames.
ImageAnimationController(base::SingleThreadTaskRunner* task_runner,
- base::Closure invalidation_callback);
+ base::RepeatingClosure invalidation_callback,
+ bool enable_image_animation_resync);
~ImageAnimationController();
// Called to update the state for a PaintImage received in a new recording.
@@ -96,11 +99,17 @@ class CC_EXPORT ImageAnimationController {
size_t GetFrameIndexForImage(PaintImage::Id paint_image_id,
WhichTree tree) const;
+ void set_did_navigate() { did_navigate_ = true; };
+
const base::flat_set<AnimationDriver*>& GetDriversForTesting(
PaintImage::Id paint_image_id) const;
size_t GetLastNumOfFramesSkippedForTesting(
PaintImage::Id paint_image_id) const;
+ size_t animation_state_map_size_for_testing() {
+ return animation_state_map_.size();
+ }
+
private:
class AnimationState {
public:
@@ -110,7 +119,7 @@ class CC_EXPORT ImageAnimationController {
~AnimationState();
bool ShouldAnimate() const;
- bool AdvanceFrame(base::TimeTicks now);
+ bool AdvanceFrame(base::TimeTicks now, bool enable_image_animation_resync);
void UpdateMetadata(const DiscardableImageMap::AnimatedImageMetadata& data);
void PushPendingToActive();
@@ -193,7 +202,7 @@ class CC_EXPORT ImageAnimationController {
class DelayedNotifier {
public:
DelayedNotifier(base::SingleThreadTaskRunner* task_runner,
- base::Closure closure);
+ base::RepeatingClosure closure);
~DelayedNotifier();
void Schedule(base::TimeTicks now, base::TimeTicks notification_time);
@@ -204,7 +213,7 @@ class CC_EXPORT ImageAnimationController {
void Notify();
base::SingleThreadTaskRunner* task_runner_;
- base::Closure closure_;
+ base::RepeatingClosure closure_;
// Set if a notification is currently pending.
base::Optional<base::TimeTicks> pending_notification_time_;
@@ -231,6 +240,10 @@ class CC_EXPORT ImageAnimationController {
PaintImageIdFlatSet images_animated_on_sync_tree_;
DelayedNotifier notifier_;
+
+ const bool enable_image_animation_resync_;
+
+ bool did_navigate_ = false;
};
} // namespace cc
diff --git a/chromium/cc/trees/image_animation_controller_unittest.cc b/chromium/cc/trees/image_animation_controller_unittest.cc
index 1a4c486dc14..ea59f849c4c 100644
--- a/chromium/cc/trees/image_animation_controller_unittest.cc
+++ b/chromium/cc/trees/image_animation_controller_unittest.cc
@@ -78,7 +78,8 @@ class ImageAnimationControllerTest : public testing::Test {
base::Bind(&ImageAnimationControllerTest::RequestInvalidation,
base::Unretained(this));
controller_ = std::make_unique<ImageAnimationController>(
- task_runner_.get(), invalidation_callback);
+ task_runner_.get(), invalidation_callback,
+ GetEnableImageAnimationResync());
now_ += base::TimeDelta::FromSeconds(10);
}
@@ -151,6 +152,8 @@ class ImageAnimationControllerTest : public testing::Test {
void AdvanceNow(base::TimeDelta delta) { now_ += delta; }
+ virtual bool GetEnableImageAnimationResync() const { return true; }
+
base::TimeTicks now_;
int invalidation_count_ = 0;
std::unique_ptr<ImageAnimationController> controller_;
@@ -734,4 +737,154 @@ TEST_F(ImageAnimationControllerTest, ResetAnimations) {
controller_->UnregisterAnimationDriver(data.paint_image_id, &driver);
}
+TEST_F(ImageAnimationControllerTest, ResetAnimationStateMapOnNavigation) {
+ std::vector<FrameMetadata> first_image_frames = {
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(2)),
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(3))};
+ DiscardableImageMap::AnimatedImageMetadata first_data(
+ PaintImage::GetNextId(), PaintImage::CompletionState::DONE,
+ first_image_frames, kAnimationLoopOnce, 0);
+ controller_->UpdateAnimatedImage(first_data);
+ FakeAnimationDriver first_driver;
+ controller_->RegisterAnimationDriver(first_data.paint_image_id,
+ &first_driver);
+
+ std::vector<FrameMetadata> second_image_frames = {
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(5)),
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(3))};
+ DiscardableImageMap::AnimatedImageMetadata second_data(
+ PaintImage::GetNextId(), PaintImage::CompletionState::DONE,
+ second_image_frames, kAnimationLoopOnce, 0);
+ controller_->UpdateAnimatedImage(second_data);
+ FakeAnimationDriver second_driver;
+ controller_->RegisterAnimationDriver(second_data.paint_image_id,
+ &second_driver);
+
+ controller_->AnimateForSyncTree(now_);
+
+ controller_->UnregisterAnimationDriver(first_data.paint_image_id,
+ &first_driver);
+ EXPECT_EQ(controller_->animation_state_map_size_for_testing(), 2u);
+
+ // Fake navigation and activation.
+ controller_->set_did_navigate();
+ controller_->DidActivate();
+
+ // Animation state map entries without drivers will be purged on navigation.
+ EXPECT_EQ(controller_->animation_state_map_size_for_testing(), 1u);
+
+ controller_->UnregisterAnimationDriver(second_data.paint_image_id,
+ &second_driver);
+
+ EXPECT_EQ(controller_->animation_state_map_size_for_testing(), 1u);
+}
+
+class ImageAnimationControllerNoResyncTest
+ : public ImageAnimationControllerTest {
+ protected:
+ bool GetEnableImageAnimationResync() const override { return false; }
+};
+
+TEST_F(ImageAnimationControllerNoResyncTest, NoSyncCutoffAfterIdle) {
+ std::vector<FrameMetadata> frames = {
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(2)),
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(3))};
+
+ DiscardableImageMap::AnimatedImageMetadata data(
+ PaintImage::GetNextId(), PaintImage::CompletionState::DONE, frames,
+ kAnimationLoopInfinite, 0);
+ controller_->UpdateAnimatedImage(data);
+ FakeAnimationDriver driver;
+ controller_->RegisterAnimationDriver(data.paint_image_id, &driver);
+ controller_->UpdateStateFromDrivers(now_);
+
+ // Advance the first frame.
+ task_runner_->VerifyDelay(base::TimeDelta());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(invalidation_count_, 1);
+ auto animated_images = controller_->AnimateForSyncTree(now_);
+ EXPECT_EQ(animated_images.size(), 0u);
+ EXPECT_EQ(controller_->GetFrameIndexForImage(data.paint_image_id,
+ WhichTree::PENDING_TREE),
+ 0u);
+ EXPECT_EQ(controller_->GetFrameIndexForImage(data.paint_image_id,
+ WhichTree::ACTIVE_TREE),
+ 0u);
+ controller_->DidActivate();
+
+ // Invalidation request for the second frame.
+ task_runner_->VerifyDelay(frames[0].duration);
+
+ // Advance the time by 10 min (divisible by animation duration) and first
+ // frame duration.
+ AdvanceNow(base::TimeDelta::FromMinutes(10) + frames[0].duration);
+
+ // Animate again, it should not restart from the start. Should display second
+ // animation frame.
+ animated_images = controller_->AnimateForSyncTree(now_);
+ EXPECT_EQ(animated_images.size(), 1u);
+ EXPECT_EQ(controller_->GetFrameIndexForImage(data.paint_image_id,
+ WhichTree::PENDING_TREE),
+ 1u);
+ EXPECT_EQ(controller_->GetFrameIndexForImage(data.paint_image_id,
+ WhichTree::ACTIVE_TREE),
+ 0u);
+ controller_->DidActivate();
+
+ // New invalidation request since the desired invalidation time changed.
+ task_runner_->VerifyDelay(frames[1].duration);
+ invalidation_count_ = 0;
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(invalidation_count_, 1);
+
+ controller_->UnregisterAnimationDriver(data.paint_image_id, &driver);
+}
+
+TEST_F(ImageAnimationControllerNoResyncTest, SkipsLoopsAfterFirstIteration) {
+ std::vector<FrameMetadata> frames = {
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(2)),
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(3)),
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(4)),
+ FrameMetadata(true, base::TimeDelta::FromMilliseconds(5))};
+
+ DiscardableImageMap::AnimatedImageMetadata data(
+ PaintImage::GetNextId(), PaintImage::CompletionState::PARTIALLY_DONE,
+ frames, kAnimationLoopInfinite, 0);
+ controller_->UpdateAnimatedImage(data);
+ FakeAnimationDriver driver;
+ controller_->RegisterAnimationDriver(data.paint_image_id, &driver);
+ controller_->UpdateStateFromDrivers(now_);
+
+ // Perform the first loop while the image is partially loaded, until the third
+ // frame.
+ LoopOnceNoDelay(data.paint_image_id, frames, 3u, 0);
+
+ // The invalidation has been scheduled with a delay for the third frame's
+ // duration.
+ task_runner_->VerifyDelay(frames[2].duration);
+
+ // |now_| is set to the desired time for the fourth frame. Advance further so
+ // we reach the time for the second frame.
+ AdvanceNow(frames[3].duration + frames[0].duration);
+
+ // Finish the image load.
+ data.completion_state = PaintImage::CompletionState::DONE;
+ controller_->UpdateAnimatedImage(data);
+ controller_->UpdateStateFromDrivers(now_);
+
+ // Invalidation is scheduled immediately because we are way past the desired
+ // time. We skip frames even after the image is loaded.
+ task_runner_->VerifyDelay(base::TimeDelta());
+ auto animated_images = controller_->AnimateForSyncTree(now_);
+ EXPECT_EQ(animated_images.size(), 1u);
+ EXPECT_EQ(animated_images.count(data.paint_image_id), 1u);
+ EXPECT_EQ(controller_->GetFrameIndexForImage(data.paint_image_id,
+ WhichTree::PENDING_TREE),
+ 1u);
+ EXPECT_EQ(controller_->GetFrameIndexForImage(data.paint_image_id,
+ WhichTree::ACTIVE_TREE),
+ 2u);
+ controller_->UnregisterAnimationDriver(data.paint_image_id, &driver);
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/latency_info_swap_promise.cc b/chromium/cc/trees/latency_info_swap_promise.cc
index 3dcaf1ecf4b..6ebf5352014 100644
--- a/chromium/cc/trees/latency_info_swap_promise.cc
+++ b/chromium/cc/trees/latency_info_swap_promise.cc
@@ -33,7 +33,9 @@ LatencyInfoSwapPromise::LatencyInfoSwapPromise(const ui::LatencyInfo& latency)
LatencyInfoSwapPromise::~LatencyInfoSwapPromise() = default;
-void LatencyInfoSwapPromise::WillSwap(viz::CompositorFrameMetadata* metadata) {
+void LatencyInfoSwapPromise::WillSwap(
+ viz::CompositorFrameMetadata* metadata,
+ FrameTokenAllocator* frame_token_allocator) {
DCHECK(!latency_.terminated());
metadata->latency_info.push_back(latency_);
}
diff --git a/chromium/cc/trees/latency_info_swap_promise.h b/chromium/cc/trees/latency_info_swap_promise.h
index 2b23d67dc80..bdccb3eb546 100644
--- a/chromium/cc/trees/latency_info_swap_promise.h
+++ b/chromium/cc/trees/latency_info_swap_promise.h
@@ -19,7 +19,8 @@ class CC_EXPORT LatencyInfoSwapPromise : public SwapPromise {
~LatencyInfoSwapPromise() override;
void DidActivate() override {}
- void WillSwap(viz::CompositorFrameMetadata* metadata) override;
+ void WillSwap(viz::CompositorFrameMetadata* metadata,
+ FrameTokenAllocator* frame_token_allocator) override;
void DidSwap() override;
DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override;
void OnCommit() override;
diff --git a/chromium/cc/trees/layer_tree_frame_sink.h b/chromium/cc/trees/layer_tree_frame_sink.h
index c0971b59bca..f61c7a6c019 100644
--- a/chromium/cc/trees/layer_tree_frame_sink.h
+++ b/chromium/cc/trees/layer_tree_frame_sink.h
@@ -35,6 +35,7 @@ struct BeginFrameAck;
namespace cc {
class LayerTreeFrameSinkClient;
+class LayerTreeHostImpl;
// An interface for submitting CompositorFrames to a display compositor
// which will compose frames from multiple clients to show on screen to the
@@ -114,6 +115,10 @@ class CC_EXPORT LayerTreeFrameSink : public viz::ContextLostObserver {
return shared_bitmap_manager_;
}
+ // Generate hit test region list based on LayerTreeHostImpl, the data will be
+ // submitted with compositor frame.
+ virtual void UpdateHitTestData(const LayerTreeHostImpl* host_impl) {}
+
// If supported, this sets the viz::LocalSurfaceId the LayerTreeFrameSink will
// use to submit a CompositorFrame.
virtual void SetLocalSurfaceId(const viz::LocalSurfaceId& local_surface_id) {}
diff --git a/chromium/cc/trees/layer_tree_frame_sink_unittest.cc b/chromium/cc/trees/layer_tree_frame_sink_unittest.cc
index 7ccde476682..8ac72b45da5 100644
--- a/chromium/cc/trees/layer_tree_frame_sink_unittest.cc
+++ b/chromium/cc/trees/layer_tree_frame_sink_unittest.cc
@@ -4,7 +4,6 @@
#include "cc/trees/layer_tree_frame_sink.h"
-#include "base/memory/ptr_util.h"
#include "base/test/test_simple_task_runner.h"
#include "cc/test/fake_layer_tree_frame_sink_client.h"
#include "components/viz/common/quads/compositor_frame.h"
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index 7ea19e9fbd8..d8bf091317a 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -17,7 +17,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/location.h"
-#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_math.h"
#include "base/single_thread_task_runner.h"
@@ -28,6 +28,7 @@
#include "base/timer/elapsed_timer.h"
#include "base/trace_event/trace_event.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"
@@ -336,7 +337,7 @@ void LayerTreeHost::FinishCommitOnImplThread(
if (did_navigate) {
TRACE_EVENT0("cc,benchmark", "LayerTreeHost::DidNavigate");
proxy_->ClearHistoryOnNavigation();
- host_impl->ClearImageCacheOnNavigation();
+ host_impl->DidNavigate();
}
{
@@ -669,12 +670,16 @@ bool LayerTreeHost::UpdateLayers() {
micro_benchmark_controller_.DidUpdateLayers();
if (const char* client_name = GetClientNameForMetrics()) {
+ auto elapsed = timer.Elapsed().InMicroseconds();
+
std::string histogram_name =
- base::StringPrintf("Compositing.%s.LayersUpdateTime.%d", client_name,
- GetLayersUpdateTimeHistogramBucket(NumLayers()));
- base::Histogram::FactoryGet(histogram_name, 0, 10000000, 50,
- base::HistogramBase::kUmaTargetedHistogramFlag)
- ->Add(timer.Elapsed().InMicroseconds());
+ 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;
@@ -1050,11 +1055,6 @@ void LayerTreeHost::SetViewportSizeAndScale(
const gfx::Size& device_viewport_size,
float device_scale_factor,
const viz::LocalSurfaceId& local_surface_id) {
- DCHECK(!local_surface_id.is_valid() || !device_viewport_size.IsEmpty())
- << "A valid LocalSurfaceId has been provided with an empty device "
- "viewport size "
- << local_surface_id;
- // TODO(ccameron): Add CHECKs here for surface invariants violations.
if (settings_.enable_surface_synchronization)
SetLocalSurfaceId(local_surface_id);
@@ -1080,9 +1080,23 @@ void LayerTreeHost::SetViewportSizeAndScale(
if (changed) {
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
+#if defined(OS_MACOSX)
+ // TODO(ccameron): This check is not valid on Aura or Mus yet, but should
+ // be.
+ CHECK(!has_pushed_local_surface_id_ || !local_surface_id_.is_valid());
+#endif
}
}
+void LayerTreeHost::SetViewportVisibleRect(const gfx::Rect& visible_rect) {
+ if (visible_rect == viewport_visible_rect_)
+ return;
+
+ viewport_visible_rect_ = visible_rect;
+ SetPropertyTreesNeedRebuild();
+ SetNeedsCommit();
+}
+
void LayerTreeHost::SetBrowserControlsHeight(float top_height,
float bottom_height,
bool shrink) {
@@ -1171,6 +1185,7 @@ void LayerTreeHost::SetLocalSurfaceId(
if (local_surface_id_ == local_surface_id)
return;
local_surface_id_ = local_surface_id;
+ has_pushed_local_surface_id_ = false;
UpdateDeferCommitsInternal();
SetNeedsCommit();
}
@@ -1361,6 +1376,7 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) {
tree_impl->set_content_source_id(content_source_id_);
tree_impl->set_local_surface_id(local_surface_id_);
+ has_pushed_local_surface_id_ = true;
if (pending_page_scale_animation_) {
tree_impl->SetPendingPageScaleAnimation(
@@ -1389,6 +1405,7 @@ void LayerTreeHost::PushLayerTreeHostPropertiesTo(
RecordGpuRasterizationHistogram(host_impl);
host_impl->SetViewportSize(device_viewport_size_);
+ host_impl->SetViewportVisibleRect(viewport_visible_rect_);
host_impl->SetDebugState(debug_state_);
}
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index 01c876d48d1..9aecadafd1e 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -296,6 +296,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
float device_scale_factor,
const viz::LocalSurfaceId& local_surface_id);
+ void SetViewportVisibleRect(const gfx::Rect& visible_rect);
+
+ gfx::Rect viewport_visible_rect() const { return viewport_visible_rect_; }
+
gfx::Size device_viewport_size() const { return device_viewport_size_; }
void SetBrowserControlsHeight(float top_height,
@@ -633,6 +637,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
uint32_t content_source_id_;
viz::LocalSurfaceId local_surface_id_;
+ // Used to detect surface invariant violations.
+ bool has_pushed_local_surface_id_ = false;
bool defer_commits_ = false;
SkColor background_color_ = SK_ColorWHITE;
@@ -641,6 +647,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
gfx::Size device_viewport_size_;
+ gfx::Rect viewport_visible_rect_;
+
bool have_scroll_event_handlers_ = false;
EventListenerProperties event_listener_properties_[static_cast<size_t>(
EventListenerClass::kNumClasses)];
diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc
index b9ad8b4a2a3..329e9cd4b7e 100644
--- a/chromium/cc/trees/layer_tree_host_common_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <memory>
#include <set>
+#include <tuple>
#include <vector>
#include "base/memory/ptr_util.h"
@@ -4489,7 +4490,7 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
active_child->effect_tree_index()));
}
-using LCDTextTestParam = std::tr1::tuple<bool, bool, bool>;
+using LCDTextTestParam = std::tuple<bool, bool, bool>;
class LCDTextTest : public LayerTreeHostCommonTestBase,
public testing::TestWithParam<LCDTextTestParam> {
public:
@@ -4505,8 +4506,8 @@ class LCDTextTest : public LayerTreeHostCommonTestBase,
LayerTreeSettings LCDTextTestLayerTreeSettings() {
LayerTreeSettings settings = VerifyTreeCalcsLayerTreeSettings();
- can_use_lcd_text_ = std::tr1::get<0>(GetParam());
- layers_always_allowed_lcd_text_ = std::tr1::get<1>(GetParam());
+ can_use_lcd_text_ = std::get<0>(GetParam());
+ layers_always_allowed_lcd_text_ = std::get<1>(GetParam());
settings.can_use_lcd_text = can_use_lcd_text_;
settings.layers_always_allowed_lcd_text = layers_always_allowed_lcd_text_;
return settings;
@@ -4547,8 +4548,7 @@ class LCDTextTest : public LayerTreeHostCommonTestBase,
child_->SetBounds(gfx::Size(1, 1));
grand_child_->SetBounds(gfx::Size(1, 1));
- child_->test_properties()->force_render_surface =
- std::tr1::get<2>(GetParam());
+ child_->test_properties()->force_render_surface = std::get<2>(GetParam());
}
bool can_use_lcd_text_;
@@ -4885,10 +4885,16 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
- EXPECT_TRUE(root_layer->has_copy_requests_in_target_subtree());
- EXPECT_TRUE(copy_grand_parent_layer->has_copy_requests_in_target_subtree());
- EXPECT_TRUE(copy_parent_layer->has_copy_requests_in_target_subtree());
- EXPECT_TRUE(copy_layer->has_copy_requests_in_target_subtree());
+ auto& effect_tree =
+ root_layer->layer_tree_impl()->property_trees()->effect_tree;
+ EXPECT_TRUE(effect_tree.Node(root_layer->effect_tree_index())
+ ->subtree_has_copy_request);
+ EXPECT_TRUE(effect_tree.Node(copy_grand_parent_layer->effect_tree_index())
+ ->subtree_has_copy_request);
+ EXPECT_TRUE(effect_tree.Node(copy_parent_layer->effect_tree_index())
+ ->subtree_has_copy_request);
+ EXPECT_TRUE(effect_tree.Node(copy_layer->effect_tree_index())
+ ->subtree_has_copy_request);
// We should have four render surfaces, one for the root, one for the grand
// parent since it has opacity and two drawing descendants, one for the parent
@@ -10483,5 +10489,28 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTrilinearFiltering) {
GetRenderSurface(parent)->DrawableContentRect());
}
+TEST_F(LayerTreeHostCommonTest, VisibleRectClippedByViewport) {
+ FakeImplTaskRunnerProvider task_runner_provider;
+ TestTaskGraphRunner task_graph_runner;
+ FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
+
+ gfx::Size root_layer_size = gfx::Size(300, 500);
+ gfx::Size device_viewport_size = gfx::Size(300, 600);
+ gfx::Rect viewport_visible_rect = gfx::Rect(100, 100, 200, 200);
+
+ host_impl.SetViewportSize(device_viewport_size);
+ host_impl.SetViewportVisibleRect(viewport_visible_rect);
+ host_impl.active_tree()->SetRootLayerForTesting(
+ LayerImpl::Create(host_impl.active_tree(), 1));
+
+ LayerImpl* root = host_impl.active_tree()->root_layer_for_testing();
+ root->SetBounds(root_layer_size);
+ root->SetDrawsContent(true);
+ ExecuteCalculateDrawProperties(root);
+
+ EXPECT_EQ(viewport_visible_rect, root->visible_layer_rect());
+ EXPECT_EQ(gfx::Rect(root_layer_size), root->drawable_content_rect());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index 965f07783fa..910862ce9a8 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -65,6 +65,7 @@
#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"
@@ -77,8 +78,10 @@
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/transform_node.h"
#include "cc/trees/tree_synchronizer.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/delay_based_time_source.h"
+#include "components/viz/common/gpu/texture_allocation.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "components/viz/common/quads/frame_deadline.h"
@@ -86,6 +89,7 @@
#include "components/viz/common/quads/shared_quad_state.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/resources/bitmap_allocation.h"
#include "components/viz/common/traced_value.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
@@ -98,6 +102,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/skia_util.h"
namespace cc {
namespace {
@@ -170,16 +175,15 @@ DEFINE_SCOPED_UMA_HISTOGRAM_TIMER(PendingTreeDurationHistogramTimer,
"Scheduling.%s.PendingTreeDuration");
DEFINE_SCOPED_UMA_HISTOGRAM_TIMER(PendingTreeRasterDurationHistogramTimer,
"Scheduling.%s.PendingTreeRasterDuration");
-DEFINE_SCOPED_UMA_HISTOGRAM_TIMER(
- ImageInvalidationUpdateDurationHistogramTimer,
- "Scheduling.%s.ImageInvalidationUpdateDuration");
-
-LayerTreeHostImpl::FrameData::FrameData()
- : render_surface_list(nullptr),
- has_no_damage(false),
- may_contain_video(false) {}
+LayerTreeHostImpl::FrameData::FrameData() = default;
LayerTreeHostImpl::FrameData::~FrameData() = default;
+LayerTreeHostImpl::UIResourceData::UIResourceData() = default;
+LayerTreeHostImpl::UIResourceData::~UIResourceData() = default;
+LayerTreeHostImpl::UIResourceData::UIResourceData(UIResourceData&&) noexcept =
+ default;
+LayerTreeHostImpl::UIResourceData& LayerTreeHostImpl::UIResourceData::operator=(
+ UIResourceData&&) = default;
std::unique_ptr<LayerTreeHostImpl> LayerTreeHostImpl::Create(
const LayerTreeSettings& settings,
@@ -257,6 +261,14 @@ LayerTreeHostImpl::LayerTreeHostImpl(
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_(
+ GetTaskRunner(),
+ base::BindRepeating(
+ &LayerTreeHostImpl::RequestInvalidationForAnimatedImages,
+ base::Unretained(this)),
+ settings_.enable_image_animation_resync),
default_color_space_id_(gfx::ColorSpace::GetNextId()),
default_color_space_(gfx::ColorSpace::CreateSRGB()) {
DCHECK(mutator_host_);
@@ -283,16 +295,6 @@ LayerTreeHostImpl::LayerTreeHostImpl(
settings.top_controls_hide_threshold);
tile_manager_.SetDecodedImageTracker(&decoded_image_tracker_);
-
- if (settings_.enable_image_animations) {
- // It is safe to use base::Unretained here since we will outlive the
- // ImageAnimationController.
- base::Closure invalidation_callback =
- base::Bind(&LayerTreeHostImpl::RequestInvalidationForAnimatedImages,
- base::Unretained(this));
- image_animation_controller_.emplace(GetTaskRunner(),
- std::move(invalidation_callback));
- }
}
LayerTreeHostImpl::~LayerTreeHostImpl() {
@@ -362,11 +364,6 @@ void LayerTreeHostImpl::CommitComplete() {
if (input_handler_client_ && impl_thread_phase_ == ImplThreadPhase::IDLE)
input_handler_client_->DeliverInputForBeginFrame();
- UpdateSyncTreeAfterCommitOrImplSideInvalidation();
- micro_benchmark_controller_.DidCompleteCommit();
-}
-
-void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
if (CommitToActiveTree()) {
active_tree_->HandleScrollbarShowRequestsFromMain();
@@ -385,6 +382,11 @@ void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
else
AnimatePendingTreeAfterCommit();
+ UpdateSyncTreeAfterCommitOrImplSideInvalidation();
+ micro_benchmark_controller_.DidCompleteCommit();
+}
+
+void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
// LayerTreeHost may have changed the GPU rasterization flags state, which
// may require an update of the tree resources.
UpdateTreeResourcesForGpuRasterizationIfNeeded();
@@ -410,22 +412,16 @@ void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
// Defer invalidating images until UpdateDrawProperties is performed since
// that updates whether an image should be animated based on its visibility
// and the updated data for the image from the main frame.
- {
- ImageInvalidationUpdateDurationHistogramTimer image_invalidation_timer;
PaintImageIdFlatSet images_to_invalidate =
tile_manager_.TakeImagesToInvalidateOnSyncTree();
if (ukm_manager_)
ukm_manager_->AddCheckerboardedImages(images_to_invalidate.size());
- if (image_animation_controller_.has_value()) {
- const auto& animated_images =
- image_animation_controller_.value().AnimateForSyncTree(
- CurrentBeginFrameArgs().frame_time);
- images_to_invalidate.insert(animated_images.begin(),
- animated_images.end());
- }
+ const auto& animated_images =
+ image_animation_controller_.AnimateForSyncTree(
+ CurrentBeginFrameArgs().frame_time);
+ images_to_invalidate.insert(animated_images.begin(), animated_images.end());
sync_tree()->InvalidateRegionForImages(images_to_invalidate);
- }
// Note that it is important to push the state for checkerboarded and animated
// images prior to PrepareTiles here when committing to the active tree. This
@@ -500,14 +496,18 @@ bool LayerTreeHostImpl::CanDraw() const {
}
void LayerTreeHostImpl::AnimatePendingTreeAfterCommit() {
- AnimateInternal(false);
+ // Animate the pending tree layer animations to put them at initial positions
+ // and starting state. There is no need to run other animations on pending
+ // tree because they depend on user inputs so the state is identical to what
+ // the active tree has.
+ AnimateLayers(CurrentBeginFrameArgs().frame_time, /* is_active_tree */ false);
}
void LayerTreeHostImpl::Animate() {
- AnimateInternal(true);
+ AnimateInternal();
}
-void LayerTreeHostImpl::AnimateInternal(bool active_tree) {
+void LayerTreeHostImpl::AnimateInternal() {
DCHECK(task_runner_provider_->IsImplThread());
base::TimeTicks monotonic_time = CurrentBeginFrameArgs().frame_time;
@@ -532,19 +532,17 @@ void LayerTreeHostImpl::AnimateInternal(bool active_tree) {
}
did_animate |= AnimatePageScale(monotonic_time);
- did_animate |= AnimateLayers(monotonic_time, active_tree);
+ did_animate |= AnimateLayers(monotonic_time, /* is_active_tree */ true);
did_animate |= AnimateScrollbars(monotonic_time);
did_animate |= AnimateBrowserControls(monotonic_time);
- if (active_tree) {
// Animating stuff can change the root scroll offset, so inform the
// synchronous input handler.
- UpdateRootLayerStateForSynchronousInputHandler();
- if (did_animate) {
- // If the tree changed, then we want to draw at the end of the current
- // frame.
- SetNeedsRedraw();
- }
+ UpdateRootLayerStateForSynchronousInputHandler();
+ if (did_animate) {
+ // If the tree changed, then we want to draw at the end of the current
+ // frame.
+ SetNeedsRedraw();
}
}
@@ -1188,6 +1186,8 @@ 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);
if (!CommitToActiveTree())
CreatePendingTree();
@@ -1521,11 +1521,10 @@ void LayerTreeHostImpl::RequestImplSideInvalidationForCheckerImagedTiles() {
size_t LayerTreeHostImpl::GetFrameIndexForImage(const PaintImage& paint_image,
WhichTree tree) const {
- DCHECK(image_animation_controller_.has_value());
if (!paint_image.ShouldAnimate())
return paint_image.frame_index();
- return image_animation_controller_->GetFrameIndexForImage(
+ return image_animation_controller_.GetFrameIndexForImage(
paint_image.stable_id(), tree);
}
@@ -1843,6 +1842,11 @@ RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata() {
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;
+
+ active_tree_->GetViewportSelection(&metadata.selection);
+
return metadata;
}
@@ -1901,7 +1905,7 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
if (active_tree_->hud_layer()) {
TRACE_EVENT0("cc", "DrawLayers.UpdateHudTexture");
active_tree_->hud_layer()->UpdateHudTexture(
- draw_mode, resource_provider_.get(),
+ draw_mode, layer_tree_frame_sink_, resource_provider_.get(),
// 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,
@@ -1916,12 +1920,12 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
frame->use_default_lower_bound_deadline);
metadata.activation_dependencies = std::move(frame->activation_dependencies);
- active_tree()->FinishSwapPromises(&metadata);
+ active_tree()->FinishSwapPromises(&metadata, &frame_token_allocator_);
if (render_frame_metadata_observer_) {
RenderFrameMetadata render_frame_metadata = MakeRenderFrameMetadata();
render_frame_metadata_observer_->OnRenderFrameSubmission(
- render_frame_metadata);
+ std::move(render_frame_metadata));
}
metadata.latency_info.emplace_back(ui::SourceEventType::FRAME);
@@ -1963,8 +1967,14 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
compositor_frame.render_pass_list = std::move(frame->render_passes);
// TODO(fsamuel): Once all clients get their viz::LocalSurfaceId from their
// parent, the viz::LocalSurfaceId should hang off CompositorFrameMetadata.
- if (settings_.enable_surface_synchronization &&
- active_tree()->local_surface_id().is_valid()) {
+ if (settings_.enable_surface_synchronization) {
+ // If surface synchronization is on, we should always have a valid
+ // LocalSurfaceId in LayerTreeImpl unless we don't have a scheduler because
+ // without a scheduler commits are not deferred and LayerTrees without valid
+ // LocalSurfaceId might slip through, but single-thread-without-scheduler
+ // mode is only used in tests so it doesn't matter.
+ CHECK(!settings_.single_thread_proxy_scheduler ||
+ active_tree()->local_surface_id().is_valid());
layer_tree_frame_sink_->SetLocalSurfaceId(
active_tree()->local_surface_id());
last_draw_local_surface_id_ = active_tree()->local_surface_id();
@@ -1977,6 +1987,10 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
base::StringPrintf("Compositing.%s.CompositorFrame.Quads", client_name),
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
@@ -2065,6 +2079,19 @@ void LayerTreeHostImpl::GetGpuRasterizationCapabilities(
if (!*gpu_rasterization_enabled && !settings_.gpu_rasterization_forced)
return;
+ if (use_oop_rasterization_) {
+ *gpu_rasterization_supported = true;
+ *supports_disable_msaa = caps.multisample_compatibility;
+ // For OOP raster, the gpu service side will disable msaa if the
+ // requested samples are not enough. GPU raster does this same
+ // logic below client side.
+ *max_msaa_samples = RequestedMSAASampleCount();
+ return;
+ }
+
+ if (!context_provider->ContextSupport()->HasGrContextSupport())
+ return;
+
// Do not check GrContext above. It is lazy-created, and we only want to
// create it if it might be used.
GrContext* gr_context = context_provider->GrContext();
@@ -2478,8 +2505,7 @@ void LayerTreeHostImpl::ActivateSyncTree() {
}
void LayerTreeHostImpl::ActivateStateForImages() {
- if (image_animation_controller_)
- image_animation_controller_->DidActivate();
+ image_animation_controller_.DidActivate();
tile_manager_.DidActivateSyncTree();
}
@@ -2574,12 +2600,15 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
raster_buffer_provider_ = CreateRasterBufferProvider();
if (use_gpu_rasterization_) {
+ int max_texture_size = layer_tree_frame_sink_->context_provider()
+ ->ContextCapabilities()
+ .max_texture_size;
image_decode_cache_ = std::make_unique<GpuImageDecodeCache>(
layer_tree_frame_sink_->worker_context_provider(),
- settings_.enable_oop_rasterization,
+ use_oop_rasterization_,
viz::ResourceFormatToClosestSkColorType(
settings_.preferred_tile_format),
- settings_.decoded_image_working_set_budget_bytes);
+ settings_.decoded_image_working_set_budget_bytes, max_texture_size);
} else {
image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>(
viz::ResourceFormatToClosestSkColorType(
@@ -2597,12 +2626,8 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
}
- // TODO(vmpstr): Initialize tile task limit at ctor time.
tile_manager_.SetResources(resource_pool_.get(), image_decode_cache_.get(),
task_graph_runner, raster_buffer_provider_.get(),
- is_synchronous_single_threaded_
- ? std::numeric_limits<size_t>::max()
- : settings_.scheduled_raster_task_limit,
use_gpu_rasterization_);
tile_manager_.SetCheckerImagingForceDisabled(
settings_.only_checker_images_with_gpu_raster && !use_gpu_rasterization_);
@@ -2615,11 +2640,8 @@ LayerTreeHostImpl::CreateRasterBufferProvider() {
viz::ContextProvider* compositor_context_provider =
layer_tree_frame_sink_->context_provider();
- if (!compositor_context_provider) {
- return std::make_unique<BitmapRasterBufferProvider>(
- resource_provider_.get(),
- layer_tree_frame_sink_->shared_bitmap_manager());
- }
+ if (!compositor_context_provider)
+ return std::make_unique<BitmapRasterBufferProvider>(layer_tree_frame_sink_);
viz::RasterContextProvider* worker_context_provider =
layer_tree_frame_sink_->worker_context_provider();
@@ -2627,20 +2649,14 @@ LayerTreeHostImpl::CreateRasterBufferProvider() {
DCHECK(worker_context_provider);
int msaa_sample_count = use_msaa_ ? RequestedMSAASampleCount() : 0;
- // The worker context must support oop raster to enable oop rasterization.
- bool oop_raster_enabled = settings_.enable_oop_rasterization;
- if (oop_raster_enabled) {
- viz::RasterContextProvider::ScopedRasterContextLock hold(
- worker_context_provider);
- oop_raster_enabled &=
- worker_context_provider->ContextCapabilities().supports_oop_raster;
- }
-
return std::make_unique<GpuRasterBufferProvider>(
compositor_context_provider, worker_context_provider,
- resource_provider_.get(), settings_.use_distance_field_text,
+ resource_provider_.get(),
settings_.resource_settings.use_gpu_memory_buffer_resources,
- msaa_sample_count, settings_.preferred_tile_format, oop_raster_enabled);
+ msaa_sample_count, settings_.preferred_tile_format,
+ settings_.max_gpu_raster_tile_size,
+ settings_.unpremultiply_and_dither_low_bit_depth_tiles,
+ use_oop_rasterization_);
}
bool use_zero_copy = settings_.use_zero_copy;
@@ -2680,6 +2696,14 @@ LayerImpl* LayerTreeHostImpl::ViewportMainScrollLayer() {
return viewport()->MainScrollLayer();
}
+ScrollNode* LayerTreeHostImpl::ViewportMainScrollNode() {
+ if (!ViewportMainScrollLayer())
+ return nullptr;
+
+ return active_tree_->property_trees()->scroll_tree.Node(
+ ViewportMainScrollLayer()->scroll_tree_index());
+}
+
void LayerTreeHostImpl::QueueImageDecode(int request_id,
const PaintImage& image) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
@@ -2709,13 +2733,14 @@ LayerTreeHostImpl::TakeCompletedImageDecodeRequests() {
return result;
}
-void LayerTreeHostImpl::ClearImageCacheOnNavigation() {
+void LayerTreeHostImpl::DidNavigate() {
// 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;
tile_manager_.ClearCheckerImageTracking(can_clear_decode_policy_tracking);
if (image_decode_cache_)
image_decode_cache_->ClearCache();
+ image_animation_controller_.set_did_navigate();
}
void LayerTreeHostImpl::DidChangeScrollbarVisibility() {
@@ -2729,6 +2754,7 @@ void LayerTreeHostImpl::CleanUpTileManagerResources() {
tile_manager_.FinishTasksAndCleanUp();
single_thread_synchronous_task_graph_runner_ = nullptr;
image_decode_cache_ = nullptr;
+ raster_buffer_provider_ = nullptr;
// Any resources that were allocated previously should be considered not good
// for reuse, as the RasterBufferProvider will be replaced and it may choose
// to allocate future resources differently.
@@ -2817,6 +2843,21 @@ bool LayerTreeHostImpl::InitializeRenderer(
ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kGpu,
settings_.disallow_non_exact_resource_reuse);
}
+ if (features::IsVizHitTestingSurfaceLayerEnabled())
+ layer_tree_frame_sink_->UpdateHitTestData(this);
+
+ // 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;
+ }
+ }
// Since the new context may be capable of MSAA, update status here. We don't
// need to check the return value since we are recreating all resources
@@ -2876,6 +2917,15 @@ gfx::Rect LayerTreeHostImpl::DeviceViewport() const {
return external_viewport_;
}
+void LayerTreeHostImpl::SetViewportVisibleRect(const gfx::Rect& visible_rect) {
+ if (visible_rect == viewport_visible_rect_)
+ return;
+
+ viewport_visible_rect_ = visible_rect;
+ SetFullViewportDamage();
+ active_tree_->set_needs_update_draw_properties();
+}
+
const gfx::Rect LayerTreeHostImpl::ViewportRectForTilePriority() const {
if (viewport_rect_for_tile_priority_.IsEmpty())
return DeviceViewport();
@@ -2927,8 +2977,10 @@ InputHandler::ScrollStatus LayerTreeHostImpl::TryScroll(
InputHandler::ScrollStatus scroll_status;
scroll_status.main_thread_scrolling_reasons =
MainThreadScrollingReason::kNotScrollingOnMain;
- if (!!scroll_node->main_thread_scrolling_reasons) {
- TRACE_EVENT0("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread");
+ if (scroll_node->main_thread_scrolling_reasons) {
+ TRACE_EVENT1("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread",
+ "MainThreadScrollingReason",
+ scroll_node->main_thread_scrolling_reasons);
scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
scroll_status.main_thread_scrolling_reasons =
scroll_node->main_thread_scrolling_reasons;
@@ -3109,12 +3161,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBeginImpl(
// If the viewport is scrolling and it cannot consume any delta hints, the
// scroll event will need to get bubbled if the viewport is for a guest or
// oopif.
- ScrollNode* viewport_scroll_node =
- viewport()->MainScrollLayer()
- ? active_tree_->property_trees()->scroll_tree.Node(
- viewport()->MainScrollLayer()->scroll_tree_index())
- : nullptr;
- if (active_tree_->CurrentlyScrollingNode() == viewport_scroll_node &&
+ if (active_tree_->CurrentlyScrollingNode() == ViewportMainScrollNode() &&
!viewport()->CanScroll(*scroll_state)) {
scroll_status.bubble = true;
}
@@ -3659,10 +3706,7 @@ void LayerTreeHostImpl::DistributeScrollDelta(ScrollState* scroll_state) {
std::list<ScrollNode*> current_scroll_chain;
ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree;
ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode();
- ScrollNode* viewport_scroll_node =
- viewport()->MainScrollLayer()
- ? scroll_tree.Node(viewport()->MainScrollLayer()->scroll_tree_index())
- : nullptr;
+ ScrollNode* viewport_scroll_node = ViewportMainScrollNode();
if (scroll_node) {
// TODO(bokan): The loop checks for a null parent but don't we still want to
// distribute to the root scroll node?
@@ -3751,7 +3795,7 @@ void LayerTreeHostImpl::UpdateImageDecodingHints(
void LayerTreeHostImpl::SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) {
render_frame_metadata_observer_ = std::move(observer);
- render_frame_metadata_observer_->BindToCurrentThread();
+ render_frame_metadata_observer_->BindToCurrentThread(&frame_token_allocator_);
}
InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
@@ -3815,8 +3859,13 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
accumulated_root_overscroll_.set_x(0);
if (did_scroll_y)
accumulated_root_overscroll_.set_y(0);
- gfx::Vector2dF unused_root_delta(scroll_state->delta_x(),
- scroll_state->delta_y());
+
+ gfx::Vector2dF unused_root_delta;
+ if (current_scrolling_node &&
+ current_scrolling_node == ViewportMainScrollNode()) {
+ unused_root_delta =
+ gfx::Vector2dF(scroll_state->delta_x(), scroll_state->delta_y());
+ }
// When inner viewport is unscrollable, disable overscrolls.
if (const auto* inner_viewport_scroll_node = InnerViewportScrollNode()) {
@@ -3849,6 +3898,11 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
UpdateRootLayerStateForSynchronousInputHandler();
}
+ scroll_result.current_offset = ScrollOffsetToVector2dF(
+ scroll_tree.current_scroll_offset(scroll_node->element_id));
+ float scale_factor = active_tree()->current_page_scale_factor();
+ scroll_result.current_offset.Scale(scale_factor);
+
// Run animations which need to respond to updated scroll offset.
mutator_host_->TickScrollAnimations(
CurrentBeginFrameArgs().frame_time,
@@ -3886,11 +3940,12 @@ bool LayerTreeHostImpl::SnapAtScrollEnd() {
gfx::ScrollOffset current_position =
scroll_tree.current_scroll_offset(scroll_node->element_id);
- gfx::ScrollOffset snap_position =
- data.FindSnapPosition(current_position, did_scroll_x_for_scroll_gesture_,
- did_scroll_y_for_scroll_gesture_);
- if (snap_position == current_position)
+ gfx::ScrollOffset snap_position;
+ if (!data.FindSnapPosition(current_position, did_scroll_x_for_scroll_gesture_,
+ did_scroll_y_for_scroll_gesture_,
+ &snap_position)) {
return false;
+ }
ScrollAnimationCreate(
scroll_node, ScrollOffsetToVector2dF(snap_position - current_position),
@@ -3898,6 +3953,41 @@ bool LayerTreeHostImpl::SnapAtScrollEnd() {
return true;
}
+bool LayerTreeHostImpl::GetSnapFlingInfo(
+ const gfx::Vector2dF& natural_displacement_in_viewport,
+ gfx::Vector2dF* initial_offset,
+ gfx::Vector2dF* target_offset) const {
+ const ScrollNode* scroll_node = CurrentlyScrollingNode();
+ if (!scroll_node || !scroll_node->snap_container_data.has_value())
+ return false;
+
+ const SnapContainerData& data = scroll_node->snap_container_data.value();
+ float scale_factor = active_tree()->current_page_scale_factor();
+ gfx::Vector2dF natural_displacement_in_content =
+ gfx::ScaleVector2d(natural_displacement_in_viewport, 1.f / scale_factor);
+
+ const ScrollTree& scroll_tree = active_tree()->property_trees()->scroll_tree;
+ *initial_offset = ScrollOffsetToVector2dF(
+ scroll_tree.current_scroll_offset(scroll_node->element_id));
+
+ bool did_scroll_x = did_scroll_x_for_scroll_gesture_ ||
+ natural_displacement_in_content.x() != 0;
+ bool did_scroll_y = did_scroll_y_for_scroll_gesture_ ||
+ 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)) {
+ return false;
+ }
+
+ *target_offset = ScrollOffsetToVector2dF(snap_offset);
+ target_offset->Scale(scale_factor);
+ initial_offset->Scale(scale_factor);
+ return true;
+}
+
void LayerTreeHostImpl::ClearCurrentlyScrollingNode() {
active_tree_->ClearCurrentlyScrollingNode();
did_lock_scrolling_layer_ = false;
@@ -4455,6 +4545,8 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
const gfx::Size source_size = bitmap.GetSize();
gfx::Size upload_size = bitmap.GetSize();
bool scaled = false;
+ // UIResources are assumed to be rastered in SRGB.
+ const gfx::ColorSpace& color_space = gfx::ColorSpace::CreateSRGB();
int max_texture_size = resource_provider_->max_texture_size();
if (source_size.width() > max_texture_size ||
@@ -4467,18 +4559,48 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
upload_size = gfx::ScaleToCeiledSize(source_size, scale, scale);
}
+ // For gpu compositing, a texture will be allocated and the UIResource
+ // will be uploaded into it.
+ viz::TextureAllocation texture_alloc;
+ // For software compositing, shared memory will be allocated and the
+ // UIResource will be copied into it.
+ std::unique_ptr<base::SharedMemory> shared_memory;
+ viz::SharedBitmapId shared_bitmap_id;
+
if (layer_tree_frame_sink_->context_provider()) {
- id = resource_provider_->CreateGpuTextureResource(
- upload_size, viz::ResourceTextureHint::kDefault, format,
- gfx::ColorSpace::CreateSRGB());
+ viz::ContextProvider* context_provider =
+ layer_tree_frame_sink_->context_provider();
+ texture_alloc = viz::TextureAllocation::MakeTextureId(
+ context_provider->ContextGL(), context_provider->ContextCapabilities(),
+ format, settings_.resource_settings.use_gpu_memory_buffer_resources,
+ /*for_framebuffer_attachment=*/false);
} else {
- DCHECK_EQ(format, viz::RGBA_8888);
- id = resource_provider_->CreateBitmapResource(
- upload_size, gfx::ColorSpace::CreateSRGB());
+ shared_memory =
+ viz::bitmap_allocation::AllocateMappedBitmap(upload_size, format);
+ shared_bitmap_id = viz::SharedBitmap::GenerateId();
}
if (!scaled) {
- resource_provider_->CopyToResource(id, bitmap.GetPixels(), source_size);
+ // If not scaled, we can copy the pixels 1:1 from the source bitmap to our
+ // destination backing of a texture or shared bitmap.
+ if (layer_tree_frame_sink_->context_provider()) {
+ viz::TextureAllocation::UploadStorage(
+ layer_tree_frame_sink_->context_provider()->ContextGL(),
+ layer_tree_frame_sink_->context_provider()->ContextCapabilities(),
+ format, upload_size, texture_alloc, color_space, bitmap.GetPixels());
+ } else {
+ DCHECK_EQ(bitmap.GetFormat(), UIResourceBitmap::RGBA8);
+ SkImageInfo src_info =
+ SkImageInfo::MakeN32Premul(gfx::SizeToSkISize(source_size));
+ SkImageInfo dst_info =
+ SkImageInfo::MakeN32Premul(gfx::SizeToSkISize(upload_size));
+
+ sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(
+ dst_info, shared_memory->memory(), dst_info.minRowBytes());
+ surface->getCanvas()->writePixels(
+ src_info, const_cast<uint8_t*>(bitmap.GetPixels()),
+ src_info.minRowBytes(), 0, 0);
+ }
} else {
// Only support auto-resizing for N32 textures (since this is primarily for
// scrollbars). Users of other types need to ensure they are not too big.
@@ -4489,57 +4611,170 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
float canvas_scale_y =
upload_size.height() / static_cast<float>(source_size.height());
- // Uses kPremul_SkAlphaType since that is what SkBitmap's allocN32Pixels
- // makes, and we only support the RGBA8 format here.
- SkImageInfo info = SkImageInfo::MakeN32(
- source_size.width(), source_size.height(), kPremul_SkAlphaType);
- int row_bytes = source_size.width() * 4;
+ // Uses N32Premul since that is what SkBitmap's allocN32Pixels makes, and we
+ // only support the RGBA8 format here.
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(gfx::SizeToSkISize(source_size));
SkBitmap source_bitmap;
- source_bitmap.setInfo(info, row_bytes);
+ source_bitmap.setInfo(info);
source_bitmap.setPixels(const_cast<uint8_t*>(bitmap.GetPixels()));
- // This applies the scale to draw the |bitmap| into |scaled_bitmap|.
- SkBitmap scaled_bitmap;
- scaled_bitmap.allocN32Pixels(upload_size.width(), upload_size.height());
- SkCanvas scaled_canvas(scaled_bitmap);
- scaled_canvas.scale(canvas_scale_x, canvas_scale_y);
+ // This applies the scale to draw the |bitmap| into |scaled_surface|. For
+ // gpu compositing, we scale into a software bitmap-backed SkSurface here,
+ // then upload from there into a texture. For software compositing, we scale
+ // directly into the shared memory backing.
+ sk_sp<SkSurface> scaled_surface;
+ if (layer_tree_frame_sink_->context_provider()) {
+ scaled_surface = SkSurface::MakeRasterN32Premul(upload_size.width(),
+ upload_size.height());
+ } else {
+ SkImageInfo dst_info =
+ SkImageInfo::MakeN32Premul(gfx::SizeToSkISize(upload_size));
+ scaled_surface = SkSurface::MakeRasterDirect(
+ dst_info, shared_memory->memory(), dst_info.minRowBytes());
+ }
+ SkCanvas* scaled_canvas = scaled_surface->getCanvas();
+ scaled_canvas->scale(canvas_scale_x, canvas_scale_y);
// The |canvas_scale_x| and |canvas_scale_y| may have some floating point
// error for large enough values, causing pixels on the edge to be not
// fully filled by drawBitmap(), so we ensure they start empty. (See
// crbug.com/642011 for an example.)
- scaled_canvas.clear(SK_ColorTRANSPARENT);
- scaled_canvas.drawBitmap(source_bitmap, 0, 0);
-
- auto* pixels = static_cast<uint8_t*>(scaled_bitmap.getPixels());
- resource_provider_->CopyToResource(id, pixels, upload_size);
+ scaled_canvas->clear(SK_ColorTRANSPARENT);
+ scaled_canvas->drawBitmap(source_bitmap, 0, 0);
+
+ if (layer_tree_frame_sink_->context_provider()) {
+ SkPixmap pixmap;
+ scaled_surface->peekPixels(&pixmap);
+ viz::TextureAllocation::UploadStorage(
+ layer_tree_frame_sink_->context_provider()->ContextGL(),
+ layer_tree_frame_sink_->context_provider()->ContextCapabilities(),
+ format, upload_size, texture_alloc, color_space, pixmap.addr());
+ }
}
+ // Once the backing has the UIResource inside it, we have to prepare it for
+ // export to the display compositor via ImportResource(). For gpu compositing,
+ // this requires a Mailbox+SyncToken as well. For software compositing, the
+ // SharedBitmapId must be notified to the LayerTreeFrameSink. The
+ // OnUIResourceReleased() method will be called once the resource is deleted
+ // and the display compositor is no longer using it, to free the memory
+ // allocated in this method above.
+ viz::TransferableResource transferable;
+ if (layer_tree_frame_sink_->context_provider()) {
+ gpu::gles2::GLES2Interface* gl =
+ layer_tree_frame_sink_->context_provider()->ContextGL();
+ gpu::Mailbox mailbox = gpu::Mailbox::Generate();
+ gl->ProduceTextureDirectCHROMIUM(texture_alloc.texture_id, mailbox.name);
+ gpu::SyncToken sync_token =
+ LayerTreeResourceProvider::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(
+ shared_memory.get(), upload_size, format);
+ layer_tree_frame_sink_->DidAllocateSharedBitmap(std::move(memory_handle),
+ shared_bitmap_id);
+ transferable = viz::TransferableResource::MakeSoftware(shared_bitmap_id, 0,
+ upload_size, format);
+ }
+ transferable.color_space = color_space;
+ id = resource_provider_->ImportResource(
+ transferable,
+ // The OnUIResourceReleased method is bound with a WeakPtr, but the
+ // resource backing will be deleted when the LayerTreeFrameSink is
+ // removed before shutdown, so nothing leaks if the WeakPtr is
+ // invalidated.
+ viz::SingleReleaseCallback::Create(base::BindOnce(
+ &LayerTreeHostImpl::OnUIResourceReleased, AsWeakPtr(), uid)));
+
UIResourceData data;
- data.resource_id = id;
data.opaque = bitmap.GetOpaque();
- ui_resource_map_[uid] = data;
+ data.format = format;
+ data.shared_bitmap_id = shared_bitmap_id;
+ data.shared_memory = std::move(shared_memory);
+ data.texture_id = texture_alloc.texture_id;
+ data.resource_id_for_export = id;
+ ui_resource_map_[uid] = std::move(data);
MarkUIResourceNotEvicted(uid);
}
void LayerTreeHostImpl::DeleteUIResource(UIResourceId uid) {
- viz::ResourceId id = ResourceIdForUIResource(uid);
- if (id) {
- if (has_valid_layer_tree_frame_sink_)
- resource_provider_->DeleteResource(id);
- ui_resource_map_.erase(uid);
+ auto it = ui_resource_map_.find(uid);
+ if (it != ui_resource_map_.end()) {
+ 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.
+ deleted_ui_resources_[uid] = std::move(data);
+ ui_resource_map_.erase(it);
+
+ resource_provider_->RemoveImportedResource(id);
}
MarkUIResourceNotEvicted(uid);
}
+void LayerTreeHostImpl::DeleteUIResourceBacking(
+ UIResourceData data,
+ const gpu::SyncToken& sync_token) {
+ // Resources are either software or gpu backed, not both.
+ DCHECK(!(data.shared_memory && data.texture_id));
+ if (data.shared_memory)
+ layer_tree_frame_sink_->DidDeleteSharedBitmap(data.shared_bitmap_id);
+ if (data.texture_id) {
+ gpu::gles2::GLES2Interface* gl =
+ layer_tree_frame_sink_->context_provider()->ContextGL();
+ if (sync_token.HasData())
+ gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
+ gl->DeleteTextures(1, &data.texture_id);
+ }
+ // |data| goes out of scope and deletes anything it owned.
+}
+
+void LayerTreeHostImpl::OnUIResourceReleased(UIResourceId uid,
+ const gpu::SyncToken& sync_token,
+ bool lost) {
+ auto it = deleted_ui_resources_.find(uid);
+ if (it == deleted_ui_resources_.end()) {
+ // Backing was already deleted, eg if the context was lost.
+ return;
+ }
+ UIResourceData& data = it->second;
+ // We don't recycle backings here, so |lost| is not relevant, we always delete
+ // them.
+ DeleteUIResourceBacking(std::move(data), sync_token);
+ deleted_ui_resources_.erase(it);
+}
+
void LayerTreeHostImpl::ClearUIResources() {
- for (UIResourceMap::const_iterator iter = ui_resource_map_.begin();
- iter != ui_resource_map_.end(); ++iter) {
- evicted_ui_resources_.insert(iter->first);
- resource_provider_->DeleteResource(iter->second.resource_id);
+ for (auto& pair : ui_resource_map_) {
+ UIResourceId uid = pair.first;
+ UIResourceData& data = pair.second;
+ 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).
+ DeleteUIResourceBacking(std::move(data), gpu::SyncToken());
+ // This resource is not deleted, and its |uid| is still valid, so it moves
+ // to the evicted list, not the |deleted_ui_resources_| set. Also, its
+ // backing is gone, so it would not belong in |deleted_ui_resources_|.
+ evicted_ui_resources_.insert(uid);
}
ui_resource_map_.clear();
+ for (auto& pair : deleted_ui_resources_) {
+ UIResourceData& data = pair.second;
+ // 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).
+ DeleteUIResourceBacking(std::move(data), gpu::SyncToken());
+ }
+ deleted_ui_resources_.clear();
}
void LayerTreeHostImpl::EvictAllUIResources() {
@@ -4554,14 +4789,14 @@ void LayerTreeHostImpl::EvictAllUIResources() {
viz::ResourceId LayerTreeHostImpl::ResourceIdForUIResource(
UIResourceId uid) const {
- UIResourceMap::const_iterator iter = ui_resource_map_.find(uid);
+ auto iter = ui_resource_map_.find(uid);
if (iter != ui_resource_map_.end())
- return iter->second.resource_id;
- return 0;
+ return iter->second.resource_id_for_export;
+ return viz::kInvalidResourceId;
}
bool LayerTreeHostImpl::IsUIResourceOpaque(UIResourceId uid) const {
- UIResourceMap::const_iterator iter = ui_resource_map_.find(uid);
+ auto iter = ui_resource_map_.find(uid);
DCHECK(iter != ui_resource_map_.end());
return iter->second.opaque;
}
@@ -4820,8 +5055,6 @@ void LayerTreeHostImpl::ShowScrollbarsForImplScroll(ElementId element_id) {
}
void LayerTreeHostImpl::RequestInvalidationForAnimatedImages() {
- DCHECK(image_animation_controller_);
-
// If we are animating an image, we want at least one draw of the active tree
// before a new tree is activated.
bool needs_first_draw_on_activation = true;
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index 0547246ca33..82d50cc888b 100644
--- a/chromium/cc/trees/layer_tree_host_impl.h
+++ b/chromium/cc/trees/layer_tree_host_impl.h
@@ -35,6 +35,7 @@
#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_mutator.h"
#include "cc/trees/layer_tree_settings.h"
@@ -165,6 +166,56 @@ class CC_EXPORT LayerTreeHostImpl
public MutatorHostClient,
public base::SupportsWeakPtr<LayerTreeHostImpl> {
public:
+ // This structure is used to build all the state required for producing a
+ // single CompositorFrame. The |render_passes| list becomes the set of
+ // RenderPasses in the quad, and the other fields are used for computation
+ // or become part of the CompositorFrameMetadata.
+ struct CC_EXPORT FrameData {
+ FrameData();
+ ~FrameData();
+ void AsValueInto(base::trace_event::TracedValue* value) const;
+
+ std::vector<viz::SurfaceId> activation_dependencies;
+ base::Optional<uint32_t> deadline_in_frames;
+ bool use_default_lower_bound_deadline = false;
+ std::vector<gfx::Rect> occluding_screen_space_rects;
+ std::vector<gfx::Rect> non_occluding_screen_space_rects;
+ viz::RenderPassList render_passes;
+ const RenderSurfaceList* render_surface_list = nullptr;
+ LayerImplList will_draw_layers;
+ bool has_no_damage = false;
+ bool may_contain_video = false;
+ viz::BeginFrameAck begin_frame_ack;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FrameData);
+ };
+
+ // A struct of data for a single UIResource, including the backing
+ // pixels, and metadata about it.
+ struct CC_EXPORT UIResourceData {
+ UIResourceData();
+ ~UIResourceData();
+ UIResourceData(UIResourceData&&) noexcept;
+ UIResourceData& operator=(UIResourceData&&);
+
+ bool opaque;
+ viz::ResourceFormat format;
+
+ // Backing for software compositing.
+ viz::SharedBitmapId shared_bitmap_id;
+ std::unique_ptr<base::SharedMemory> shared_memory;
+ // Backing for gpu compositing.
+ uint32_t texture_id;
+
+ // The name with which to refer to the resource in frames submitted to the
+ // display compositor.
+ viz::ResourceId resource_id_for_export;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UIResourceData);
+ };
+
static std::unique_ptr<LayerTreeHostImpl> Create(
const LayerTreeSettings& settings,
LayerTreeHostImplClient* client,
@@ -244,27 +295,6 @@ class CC_EXPORT LayerTreeHostImpl
resourceless_software_draw_ = true;
}
- struct CC_EXPORT FrameData {
- FrameData();
- ~FrameData();
- void AsValueInto(base::trace_event::TracedValue* value) const;
-
- std::vector<viz::SurfaceId> activation_dependencies;
- base::Optional<uint32_t> deadline_in_frames;
- bool use_default_lower_bound_deadline = false;
- std::vector<gfx::Rect> occluding_screen_space_rects;
- std::vector<gfx::Rect> non_occluding_screen_space_rects;
- viz::RenderPassList render_passes;
- const RenderSurfaceList* render_surface_list;
- LayerImplList will_draw_layers;
- bool has_no_damage;
- bool may_contain_video;
- viz::BeginFrameAck begin_frame_ack;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FrameData);
- };
-
virtual void DidSendBeginMainFrame() {}
virtual void BeginMainFrameAborted(
CommitEarlyOutReason reason,
@@ -452,9 +482,7 @@ class CC_EXPORT LayerTreeHostImpl
ResourcePool* resource_pool() { return resource_pool_.get(); }
ImageDecodeCache* image_decode_cache() { return image_decode_cache_.get(); }
ImageAnimationController* image_animation_controller() {
- if (!image_animation_controller_.has_value())
- return nullptr;
- return &image_animation_controller_.value();
+ return &image_animation_controller_;
}
virtual bool WillBeginImplFrame(const viz::BeginFrameArgs& args);
@@ -505,6 +533,9 @@ class CC_EXPORT LayerTreeHostImpl
void SetViewportSize(const gfx::Size& device_viewport_size);
gfx::Size device_viewport_size() const { return device_viewport_size_; }
+ void SetViewportVisibleRect(const gfx::Rect& visible_rect);
+ gfx::Rect viewport_visible_rect() const { return viewport_visible_rect_; }
+
const gfx::Transform& DrawTransform() const;
std::unique_ptr<ScrollAndScaleSet> ProcessScrollDeltas();
@@ -565,10 +596,9 @@ class CC_EXPORT LayerTreeHostImpl
virtual bool IsUIResourceOpaque(UIResourceId uid) const;
- struct UIResourceData {
- viz::ResourceId resource_id;
- bool opaque;
- };
+ bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement_in_viewport,
+ gfx::Vector2dF* initial_offset,
+ gfx::Vector2dF* target_offset) const override;
// Returns the amount of delta that can be applied to scroll_node, taking
// page scale into account.
@@ -637,12 +667,18 @@ class CC_EXPORT LayerTreeHostImpl
void SetLayerTreeMutator(std::unique_ptr<LayerTreeMutator> mutator);
+ // The viewport has two scroll nodes, corresponding to the visual and layout
+ // viewports. However, when we compute the scroll chain we include only one
+ // of these -- we call that the "main" scroll node. When scrolling it, we
+ // scroll using the Viewport class which knows how to distribute scroll
+ // between the two.
LayerImpl* ViewportMainScrollLayer();
+ ScrollNode* ViewportMainScrollNode();
void QueueImageDecode(int request_id, const PaintImage& image);
std::vector<std::pair<int, bool>> TakeCompletedImageDecodeRequests();
- void ClearImageCacheOnNavigation();
+ void DidNavigate();
bool CanConsumeDelta(const ScrollNode& scroll_node,
const ScrollState& scroll_state);
@@ -709,7 +745,7 @@ class CC_EXPORT LayerTreeHostImpl
void ReleaseTileResources();
void RecreateTileResources();
- void AnimateInternal(bool active_tree);
+ void AnimateInternal();
// The function is called to update state on the sync tree after a commit
// finishes or after the sync tree was created to invalidate content on the
@@ -756,8 +792,22 @@ class CC_EXPORT LayerTreeHostImpl
void StartScrollbarFadeRecursive(LayerImpl* layer);
void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy);
+ // Once a resource is uploaded or deleted, it is no longer an evicted id, this
+ // removes it from the evicted set, and updates if we're able to draw now that
+ // all UIResources are valid.
void MarkUIResourceNotEvicted(UIResourceId uid);
+ // Deletes all UIResource backings, and marks all the ids as evicted.
void ClearUIResources();
+ // Frees the textures/bitmaps backing the UIResource, held in the
+ // UIResourceData.
+ void DeleteUIResourceBacking(UIResourceData data,
+ const gpu::SyncToken& sync_token);
+ // Callback for when a UIResource is deleted *and* no longer in use by the
+ // display compositor. It will DeleteUIResourceBacking() if the backing was
+ // not already deleted preemptively.
+ void OnUIResourceReleased(UIResourceId uid,
+ const gpu::SyncToken& sync_token,
+ bool lost);
void NotifySwapPromiseMonitorsOfSetNeedsRedraw();
void NotifySwapPromiseMonitorsOfForwardingToMainThread();
@@ -801,12 +851,14 @@ class CC_EXPORT LayerTreeHostImpl
// active tree.
void ActivateStateForImages();
- using UIResourceMap = std::unordered_map<UIResourceId, UIResourceData>;
- UIResourceMap ui_resource_map_;
-
+ 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.
+ std::unordered_map<UIResourceId, UIResourceData> deleted_ui_resources_;
// Resources that were evicted by EvictAllUIResources. Resources are removed
// from this when they are touched by a create or destroy from the UI resource
- // request queue.
+ // request queue. The resource IDs held in here do not have any backing
+ // associated with them anymore, as that is freed at the time of eviction.
std::set<UIResourceId> evicted_ui_resources_;
LayerTreeFrameSink* layer_tree_frame_sink_;
@@ -826,6 +878,7 @@ class CC_EXPORT LayerTreeHostImpl
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_;
std::unique_ptr<RasterBufferProvider> raster_buffer_provider_;
@@ -899,6 +952,11 @@ class CC_EXPORT LayerTreeHostImpl
// overridden.
gfx::Size device_viewport_size_;
+ // Viewport clip rect passed in from the main thrad, in physical pixels.
+ // This is used for out-of-process iframes whose size exceeds the window
+ // in order to prevent full raster.
+ gfx::Rect viewport_visible_rect_;
+
// Optional top-level constraints that can be set by the LayerTreeFrameSink.
// - external_transform_ applies a transform above the root layer
// - external_viewport_ is used DrawProperties, tile management and
@@ -976,13 +1034,14 @@ class CC_EXPORT LayerTreeHostImpl
ImplThreadPhase impl_thread_phase_;
- base::Optional<ImageAnimationController> image_animation_controller_;
+ ImageAnimationController image_animation_controller_;
std::unique_ptr<UkmManager> ukm_manager_;
// 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
diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
index c44e31569ee..4c4570ee4d7 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -14,6 +14,7 @@
#include "base/command_line.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
+#include "base/optional.h"
#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -56,6 +57,7 @@
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/mutator_host.h"
+#include "cc/trees/render_frame_metadata_observer.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/transform_node.h"
@@ -176,7 +178,11 @@ class LayerTreeHostImplTest : public testing::Test,
animation_task_ = task;
requested_animation_delay_ = delay;
}
- void DidActivateSyncTree() override {}
+ void DidActivateSyncTree() override {
+ // Make sure the active tree always has a valid LocalSurfaceId.
+ host_impl_->active_tree()->set_local_surface_id(
+ viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)));
+ }
void WillPrepareTiles() override {}
void DidPrepareTiles() override {}
void DidCompletePageScaleAnimationOnImplThread() override {
@@ -236,6 +242,8 @@ class LayerTreeHostImplTest : public testing::Test,
bool init = host_impl_->InitializeRenderer(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()->set_local_surface_id(
+ viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)));
// Set the viz::BeginFrameArgs so that methods which use it are able to.
host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
BEGINFRAME_FROM_HERE, 0, 1,
@@ -681,7 +689,8 @@ 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), false);
+ SnapAreaData area_data(SnapAxis::kBoth, gfx::ScrollOffset(50, 50),
+ gfx::RectF(0, 0, 300, 300), false);
container_data.AddSnapAreaData(area_data);
overflow->test_properties()->snap_container_data.emplace(container_data);
host_impl_->active_tree()->BuildPropertyTreesForTesting();
@@ -1615,6 +1624,34 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapOnBoth) {
EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), 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);
+ EXPECT_EQ(
+ InputHandler::SCROLL_ON_IMPL_THREAD,
+ host_impl_
+ ->ScrollBegin(BeginState(scroll_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());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), overflow->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(4, 4), result.current_offset);
+
+ gfx::Vector2dF initial_offset, target_offset;
+ EXPECT_TRUE(host_impl_->GetSnapFlingInfo(gfx::Vector2dF(10, 10),
+ &initial_offset, &target_offset));
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(4, 4), initial_offset);
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), target_offset);
+}
+
TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) {
LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(200, 200));
host_impl_->SetViewportSize(gfx::Size(100, 100));
@@ -3495,6 +3532,8 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest {
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->DidBecomeActive();
host_impl_->active_tree()->HandleScrollbarShowRequestsFromMain();
+ host_impl_->active_tree()->set_local_surface_id(
+ viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)));
DrawFrame();
// SetScrollElementId will initialize the scrollbar which will cause it to
@@ -7785,6 +7824,76 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) {
}
}
+TEST_F(LayerTreeHostImplTest, NoOverscrollOnNonViewportLayers) {
+ const gfx::Size content_size(200, 200);
+ const gfx::Size viewport_size(100, 100);
+
+ LayerTreeImpl* layer_tree_impl = host_impl_->active_tree();
+
+ LayerImpl* content_layer =
+ CreateBasicVirtualViewportLayers(viewport_size, content_size);
+ LayerImpl* outer_scroll_layer = host_impl_->OuterViewportScrollLayer();
+ LayerImpl* scroll_layer = nullptr;
+
+ // Initialization: Add a nested scrolling layer, simulating a scrolling div.
+ {
+ std::unique_ptr<LayerImpl> scroll = LayerImpl::Create(layer_tree_impl, 11);
+ scroll->SetBounds(gfx::Size(400, 400));
+ scroll->SetScrollable(content_size);
+ scroll->SetElementId(LayerIdToElementIdForTesting(scroll->id()));
+ scroll->SetDrawsContent(true);
+
+ scroll_layer = scroll.get();
+
+ content_layer->test_properties()->AddChild(std::move(scroll));
+ layer_tree_impl->BuildPropertyTreesForTesting();
+ }
+
+ InputHandlerScrollResult scroll_result;
+ DrawFrame();
+
+ // Start a scroll gesture, ensure it's scrolling the subscroller.
+ {
+ host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(),
+ InputHandler::TOUCHSCREEN);
+ host_impl_->ScrollBy(
+ UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)).get());
+
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(100.f, 100.f),
+ scroll_layer->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f),
+ outer_scroll_layer->CurrentScrollOffset());
+ }
+
+ // Continue the scroll. Ensure that scrolling beyond the child's extent
+ // doesn't consume the delta but it isn't counted as overscroll.
+ {
+ InputHandlerScrollResult result = host_impl_->ScrollBy(
+ UpdateState(gfx::Point(0, 0), gfx::Vector2dF(120.f, 140.f)).get());
+
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(200.f, 200.f),
+ scroll_layer->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f),
+ outer_scroll_layer->CurrentScrollOffset());
+ EXPECT_FALSE(result.did_overscroll_root);
+ }
+
+ // Continue the scroll. Ensure that scrolling beyond the child's extent
+ // doesn't consume the delta but it isn't counted as overscroll.
+ {
+ InputHandlerScrollResult result = host_impl_->ScrollBy(
+ UpdateState(gfx::Point(0, 0), gfx::Vector2dF(20.f, 40.f)).get());
+
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(200.f, 200.f),
+ scroll_layer->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f),
+ outer_scroll_layer->CurrentScrollOffset());
+ EXPECT_FALSE(result.did_overscroll_root);
+ }
+
+ host_impl_->ScrollEnd(EndState().get());
+}
+
TEST_F(LayerTreeHostImplTest, OverscrollOnMainThread) {
InputHandlerScrollResult scroll_result;
LayerTreeSettings settings = DefaultSettings();
@@ -8260,8 +8369,8 @@ class BlendStateCheckLayer : public LayerImpl {
gfx::Size(1, 1), viz::ResourceTextureHint::kDefault, viz::RGBA_8888,
gfx::ColorSpace());
} else {
- resource_id_ = resource_provider->CreateBitmapResource(gfx::Size(1, 1),
- gfx::ColorSpace());
+ resource_id_ = resource_provider->CreateBitmapResource(
+ gfx::Size(1, 1), gfx::ColorSpace(), viz::RGBA_8888);
}
resource_provider->AllocateForTesting(resource_id_);
SetBounds(gfx::Size(10, 10));
@@ -8289,7 +8398,7 @@ class BlendStateCheckLayer : public LayerImpl {
test_blending_draw_quad->SetNew(
shared_quad_state, quad_rect_, visible_quad_rect, needs_blending,
resource_id_, gfx::RectF(0.f, 0.f, 1.f, 1.f), gfx::Size(1, 1), false,
- false, false);
+ false, false, false);
EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending());
EXPECT_EQ(has_render_surface_,
@@ -8795,7 +8904,10 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
VerifyLayerIsLargerThanViewport(last_on_draw_render_passes_);
}
- void DidActivateSyncTree() override { did_activate_pending_tree_ = true; }
+ void DidActivateSyncTree() override {
+ LayerTreeHostImplTest::DidActivateSyncTree();
+ did_activate_pending_tree_ = true;
+ }
void set_gutter_quad_material(viz::DrawQuad::Material material) {
gutter_quad_material_ = material;
@@ -8978,6 +9090,8 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
root->test_properties()->AddChild(std::move(child));
layer_tree_host_impl->active_tree()->SetRootLayerForTesting(std::move(root));
layer_tree_host_impl->active_tree()->BuildPropertyTreesForTesting();
+ layer_tree_host_impl->active_tree()->set_local_surface_id(
+ viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)));
TestFrameData frame;
@@ -13643,6 +13757,10 @@ TEST_F(LayerTreeHostImplTest, CheckerImagingTileInvalidation) {
scoped_refptr<RasterSource> raster_source =
recording_source->CreateRasterSource();
+ viz::BeginFrameArgs begin_frame_args =
+ viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ host_impl_->WillBeginImplFrame(begin_frame_args);
+
// Create the pending tree.
host_impl_->BeginCommit();
LayerTreeImpl* pending_tree = host_impl_->pending_tree();
@@ -13923,5 +14041,215 @@ 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.
+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 {
+ if (increment_counter_)
+ frame_token_allocator_->GetOrAllocateFrameToken();
+ last_metadata_ = metadata;
+ }
+
+ const base::Optional<RenderFrameMetadata>& last_metadata() const {
+ return last_metadata_;
+ }
+
+ 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 =
+ SolidColorLayerImpl::Create(host_impl_->active_tree(), root_layer_id);
+ root->SetPosition(gfx::PointF());
+ root->SetBounds(gfx::Size(10, 10));
+ root->SetDrawsContent(true);
+ root->test_properties()->force_render_surface = true;
+
+ host_impl_->active_tree()->SetRootLayerForTesting(std::move(root));
+ host_impl_->active_tree()->BuildPropertyTreesForTesting();
+
+ auto observer = std::make_unique<TestRenderFrameMetadataObserver>(false);
+ auto* observer_ptr = observer.get();
+ host_impl_->SetRenderFrameObserver(std::move(observer));
+ EXPECT_FALSE(observer_ptr->last_metadata());
+
+ // Trigger a draw-swap sequence.
+ host_impl_->SetNeedsRedraw();
+ TestFrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+ EXPECT_TRUE(host_impl_->DrawLayers(&frame));
+ host_impl_->DidDrawAllLayers(frame);
+
+ // Ensure the selection bounds propagated to the render frame metadata
+ // represent an empty selection.
+ ASSERT_TRUE(observer_ptr->last_metadata());
+ const viz::Selection<gfx::SelectionBound>& selection_1 =
+ observer_ptr->last_metadata()->selection;
+ EXPECT_EQ(gfx::SelectionBound::EMPTY, selection_1.start.type());
+ EXPECT_EQ(gfx::SelectionBound::EMPTY, selection_1.end.type());
+ EXPECT_EQ(gfx::PointF(), selection_1.start.edge_bottom());
+ EXPECT_EQ(gfx::PointF(), selection_1.start.edge_top());
+ EXPECT_FALSE(selection_1.start.visible());
+ EXPECT_FALSE(selection_1.end.visible());
+
+ // Plumb the layer-local selection bounds.
+ gfx::Point selection_top(5, 0);
+ gfx::Point selection_bottom(5, 5);
+ LayerSelection selection;
+ selection.start.type = gfx::SelectionBound::CENTER;
+ selection.start.layer_id = root_layer_id;
+ selection.start.edge_bottom = selection_bottom;
+ selection.start.edge_top = selection_top;
+ selection.end = selection.start;
+ host_impl_->active_tree()->RegisterSelection(selection);
+
+ // Trigger a draw-swap sequence.
+ host_impl_->SetNeedsRedraw();
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+ EXPECT_TRUE(host_impl_->DrawLayers(&frame));
+ host_impl_->DidDrawAllLayers(frame);
+
+ // Ensure the selection bounds have propagated to the render frame metadata.
+ ASSERT_TRUE(observer_ptr->last_metadata());
+ const viz::Selection<gfx::SelectionBound>& selection_2 =
+ observer_ptr->last_metadata()->selection;
+ EXPECT_EQ(selection.start.type, selection_2.start.type());
+ EXPECT_EQ(selection.end.type, selection_2.end.type());
+ EXPECT_EQ(gfx::PointF(selection_bottom), selection_2.start.edge_bottom());
+ EXPECT_EQ(gfx::PointF(selection_top), selection_2.start.edge_top());
+ EXPECT_TRUE(selection_2.start.visible());
+ EXPECT_TRUE(selection_2.end.visible());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
index 11c6a23a8c2..a4f98ae353a 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -4,7 +4,6 @@
#include <stddef.h>
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "cc/input/scrollbar.h"
#include "cc/layers/painted_overlay_scrollbar_layer.h"
@@ -52,6 +51,7 @@ class PaintedScrollbar : public Scrollbar {
gfx::Rect TrackRect() const override { return rect_; }
float ThumbOpacity() const override { return 1.f; }
bool NeedsPaintPart(ScrollbarPart part) const override { return true; }
+ bool HasTickmarks() const override { return false; }
void PaintPart(PaintCanvas* canvas,
ScrollbarPart part,
const gfx::Rect& content_rect) override {
@@ -150,7 +150,7 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, HugeTransformScale) {
background->AddChild(layer);
scoped_refptr<TestInProcessContextProvider> context(
- new TestInProcessContextProvider(nullptr));
+ new TestInProcessContextProvider(nullptr, 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_pixeltest_tiles.cc b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
index 7156d699a1e..bf42914b95d 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -24,6 +24,8 @@ enum RasterMode {
FULL_ONE_COPY,
PARTIAL_GPU,
FULL_GPU,
+ PARTIAL_GPU_LOW_BIT_DEPTH,
+ FULL_GPU_LOW_BIT_DEPTH,
PARTIAL_BITMAP,
FULL_BITMAP,
};
@@ -55,6 +57,18 @@ class LayerTreeHostTilesPixelTest : public LayerTreePixelTest {
settings->gpu_rasterization_forced = true;
settings->use_partial_raster = false;
break;
+ case PARTIAL_GPU_LOW_BIT_DEPTH:
+ settings->gpu_rasterization_forced = true;
+ settings->use_partial_raster = true;
+ settings->preferred_tile_format = viz::RGBA_4444;
+ settings->unpremultiply_and_dither_low_bit_depth_tiles = true;
+ break;
+ case FULL_GPU_LOW_BIT_DEPTH:
+ settings->gpu_rasterization_forced = true;
+ settings->use_partial_raster = false;
+ settings->preferred_tile_format = viz::RGBA_4444;
+ settings->unpremultiply_and_dither_low_bit_depth_tiles = true;
+ break;
}
}
@@ -81,6 +95,8 @@ class LayerTreeHostTilesPixelTest : public LayerTreePixelTest {
case FULL_ONE_COPY:
case PARTIAL_GPU:
case FULL_GPU:
+ case PARTIAL_GPU_LOW_BIT_DEPTH:
+ case FULL_GPU_LOW_BIT_DEPTH:
test_type = PIXEL_TEST_GL;
break;
case PARTIAL_BITMAP:
@@ -120,9 +136,12 @@ class BlueYellowClient : public ContentLayerClient {
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
- flags.setColor(SK_ColorBLUE);
+ // Use custom colors with 0xF2 rather than the default blue/yellow (which
+ // use 0xFF), as the default won't show dither patterns as it exactly maps
+ // to a 16-bit color.
+ flags.setColor(SkColorSetRGB(0x00, 0x00, 0xF2));
display_list->push<DrawRectOp>(gfx::RectToSkRect(blue_rect), flags);
- flags.setColor(SK_ColorYELLOW);
+ flags.setColor(SkColorSetRGB(0xF2, 0xF2, 0x00));
display_list->push<DrawRectOp>(gfx::RectToSkRect(yellow_rect), flags);
display_list->EndPaintOfUnpaired(PaintableRegion());
@@ -247,6 +266,20 @@ TEST_F(LayerTreeHostTilesTestPartialInvalidation,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png")));
}
+TEST_F(LayerTreeHostTilesTestPartialInvalidation,
+ PartialRaster_SingleThread_GpuRaster_LowBitDepth) {
+ RunRasterPixelTest(false, PARTIAL_GPU_LOW_BIT_DEPTH, picture_layer_,
+ base::FilePath(FILE_PATH_LITERAL(
+ "blue_yellow_partial_flipped_dither.png")));
+}
+
+TEST_F(LayerTreeHostTilesTestPartialInvalidation,
+ FullRaster_SingleThread_GpuRaster_LowBitDepth) {
+ RunRasterPixelTest(
+ false, FULL_GPU_LOW_BIT_DEPTH, picture_layer_,
+ base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped_dither.png")));
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc
index 19d1cdab3c3..acbd577abcd 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -11,7 +11,6 @@
#include "base/auto_reset.h"
#include "base/location.h"
-#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
@@ -1268,12 +1267,11 @@ class LayerTreeHostTestEarlyDamageCheckStops : public LayerTreeHostTest {
int damaged_frame_limit_;
};
-// Flaky on Win7 Tests (dbg)(1). https://crbug.com/813578
-#if !defined(OS_WIN)
// This behavior is specific to Android WebView, which only uses
// multi-threaded compositor.
-MULTI_THREAD_TEST_F(LayerTreeHostTestEarlyDamageCheckStops);
-#endif
+// Flaky on Win7 Tests (dbg)(1). https://crbug.com/813578
+// Flaky on linux_chromium_tsan_rel_ng. https://crbug.com/822473
+// MULTI_THREAD_TEST_F(LayerTreeHostTestEarlyDamageCheckStops);
// Verify CanDraw() is false until first commit.
class LayerTreeHostTestCantDrawBeforeCommit : public LayerTreeHostTest {
@@ -5327,7 +5325,8 @@ class TestSwapPromise : public SwapPromise {
result_->did_activate_called = true;
}
- void WillSwap(viz::CompositorFrameMetadata* metadata) override {
+ void WillSwap(viz::CompositorFrameMetadata* metadata,
+ FrameTokenAllocator* frame_token_allocator) override {
base::AutoLock lock(result_->lock);
EXPECT_FALSE(result_->did_swap_called);
EXPECT_FALSE(result_->did_not_swap_called);
@@ -8086,7 +8085,7 @@ class GpuRasterizationSucceedsWithLargeImage : public LayerTreeHostTest {
GrContext* gr_context = context_provider->GrContext();
ASSERT_TRUE(gr_context);
- const uint32_t max_texture_size = gr_context->caps()->maxTextureSize();
+ const uint32_t max_texture_size = gr_context->maxTextureSize();
ASSERT_GT(static_cast<uint32_t>(large_image_size_.width()),
max_texture_size);
}
@@ -8483,10 +8482,6 @@ class LayerTreeHostTestImageAnimation : public LayerTreeHostTest {
public:
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->enable_image_animations = true;
- }
-
virtual void AddImageOp(const PaintImage& image) = 0;
void SetupTree() override {
@@ -8597,6 +8592,20 @@ class LayerTreeHostTestImageAnimationDrawRecordShader
MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimationDrawRecordShader);
+class LayerTreeHostTestImageAnimationPaintFilter
+ : public LayerTreeHostTestImageAnimation {
+ void AddImageOp(const PaintImage& image) override {
+ auto record = sk_make_sp<PaintOpBuffer>();
+ record->push<DrawImageOp>(image, 0.f, 0.f, nullptr);
+ PaintFlags flags;
+ flags.setImageFilter(
+ sk_make_sp<RecordPaintFilter>(record, SkRect::MakeWH(500, 500)));
+ content_layer_client_.add_draw_rect(gfx::Rect(500, 500), flags);
+ }
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimationPaintFilter);
+
class LayerTreeHostTestImageAnimationSynchronousScheduling
: public LayerTreeHostTestImageAnimationDrawImage {
public:
diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation.cc b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
index da9020d54e7..0a1a2b73fc7 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
@@ -26,6 +26,7 @@
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/layer_tree_test.h"
+#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/transform_node.h"
@@ -1825,6 +1826,196 @@ class LayerTreeHostAnimationTestImplSideInvalidation
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestImplSideInvalidation);
+class LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit
+ : public LayerTreeHostAnimationTest {
+ public:
+ void SetupTree() override {
+ LayerTreeHostAnimationTest::SetupTree();
+ layer_ = FakePictureLayer::Create(&client_);
+ layer_->SetBounds(gfx::Size(4, 4));
+ client_.set_bounds(layer_->bounds());
+ layer_tree_host()->root_layer()->AddChild(layer_);
+ AttachAnimationsToTimeline();
+ animation_child_->AttachElement(layer_->element_id());
+ num_draws_ = 0;
+ }
+
+ void UpdateAnimationState(LayerTreeHostImpl* host_impl,
+ bool has_unfinished_animation) override {
+ if (!has_unfinished_animation && !did_request_impl_side_invalidation_) {
+ // The animation on the active tree has finished, now request an impl-side
+ // invalidation and verify that the final value on an impl-side pending
+ // tree is correct.
+ did_request_impl_side_invalidation_ = true;
+ host_impl->RequestImplSideInvalidationForCheckerImagedTiles();
+ }
+ }
+
+ void AfterTest() override {}
+
+ protected:
+ scoped_refptr<Layer> layer_;
+ FakeContentLayerClient client_;
+ bool did_request_impl_side_invalidation_ = false;
+ int num_draws_;
+};
+
+class ImplSideInvalidationWithoutCommitTestOpacity
+ : public LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit {
+ public:
+ void BeginTest() override {
+ AddOpacityTransitionToAnimation(animation_child_.get(), 0.04, 0.2f, 0.8f,
+ false);
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ if (num_draws_++ > 0)
+ return;
+ EXPECT_EQ(0, host_impl->active_tree()->source_frame_number());
+ LayerImpl* layer_impl = host_impl->active_tree()->LayerById(layer_->id());
+ EXPECT_FLOAT_EQ(0.2f, layer_impl->Opacity());
+ }
+
+ void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) override {
+ ASSERT_TRUE(did_request_impl_side_invalidation_);
+ EXPECT_EQ(0, host_impl->sync_tree()->source_frame_number());
+ const float expected_opacity = 0.8f;
+ LayerImpl* layer_impl = host_impl->sync_tree()->LayerById(layer_->id());
+ EXPECT_FLOAT_EQ(expected_opacity, layer_impl->Opacity());
+ EndTest();
+ }
+};
+
+MULTI_THREAD_TEST_F(ImplSideInvalidationWithoutCommitTestOpacity);
+
+class ImplSideInvalidationWithoutCommitTestTransform
+ : public LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit {
+ public:
+ void BeginTest() override {
+ AddAnimatedTransformToAnimation(animation_child_.get(), 0.04, 5, 5);
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ if (num_draws_++ > 0)
+ return;
+ EXPECT_EQ(0, host_impl->active_tree()->source_frame_number());
+ LayerImpl* layer_impl = host_impl->active_tree()->LayerById(layer_->id());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
+ layer_impl->DrawTransform());
+ }
+
+ void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) override {
+ ASSERT_TRUE(did_request_impl_side_invalidation_);
+ EXPECT_EQ(0, host_impl->sync_tree()->source_frame_number());
+ gfx::Transform expected_transform;
+ expected_transform.Translate(5.f, 5.f);
+ LayerImpl* layer_impl = host_impl->sync_tree()->LayerById(layer_->id());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform,
+ layer_impl->DrawTransform());
+ EndTest();
+ }
+};
+
+MULTI_THREAD_TEST_F(ImplSideInvalidationWithoutCommitTestTransform);
+
+class ImplSideInvalidationWithoutCommitTestFilter
+ : public LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit {
+ public:
+ void BeginTest() override {
+ AddAnimatedFilterToAnimation(animation_child_.get(), 0.04, 0.f, 1.f);
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ if (num_draws_++ > 0)
+ return;
+ EXPECT_EQ(0, host_impl->active_tree()->source_frame_number());
+ EXPECT_EQ(
+ std::string("{\"FilterOperations\":[{\"type\":5,\"amount\":0.0}]}"),
+ host_impl->active_tree()
+ ->property_trees()
+ ->effect_tree.FindNodeFromElementId(layer_->element_id())
+ ->filters.ToString());
+ }
+
+ void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) override {
+ ASSERT_TRUE(did_request_impl_side_invalidation_);
+ EXPECT_EQ(0, host_impl->sync_tree()->source_frame_number());
+ // AddAnimatedFilterToAnimation adds brightness filter which is type 5.
+ EXPECT_EQ(
+ std::string("{\"FilterOperations\":[{\"type\":5,\"amount\":1.0}]}"),
+ host_impl->sync_tree()
+ ->property_trees()
+ ->effect_tree.FindNodeFromElementId(layer_->element_id())
+ ->filters.ToString());
+ EndTest();
+ }
+};
+
+MULTI_THREAD_TEST_F(ImplSideInvalidationWithoutCommitTestFilter);
+
+class ImplSideInvalidationWithoutCommitTestScroll
+ : public LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit {
+ public:
+ void SetupTree() override {
+ LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit::SetupTree();
+
+ layer_->SetScrollable(gfx::Size(100, 100));
+ layer_->SetBounds(gfx::Size(1000, 1000));
+ client_.set_bounds(layer_->bounds());
+ layer_->SetScrollOffset(gfx::ScrollOffset(10.f, 20.f));
+ }
+
+ void BeginTest() override {
+ std::unique_ptr<ScrollOffsetAnimationCurve> curve(
+ ScrollOffsetAnimationCurve::Create(
+ gfx::ScrollOffset(500.f, 550.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);
+ ASSERT_TRUE(proxy()->SupportsImplScrolling());
+ animation_child_->AddKeyframeModel(std::move(keyframe_model));
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void WillCommit() override {
+ if (layer_tree_host()->SourceFrameNumber() == 1) {
+ // Block until the invalidation is done after animation finishes on the
+ // compositor thread. We need to make sure the pending tree has valid
+ // information based on invalidation only.
+ completion_.Wait();
+ }
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ if (num_draws_++ > 0)
+ return;
+ EXPECT_EQ(0, host_impl->active_tree()->source_frame_number());
+ LayerImpl* layer_impl = host_impl->active_tree()->LayerById(layer_->id());
+ EXPECT_VECTOR2DF_EQ(gfx::ScrollOffset(10.f, 20.f),
+ layer_impl->CurrentScrollOffset());
+ }
+
+ void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) override {
+ ASSERT_TRUE(did_request_impl_side_invalidation_);
+ EXPECT_EQ(0, host_impl->sync_tree()->source_frame_number());
+ LayerImpl* layer_impl = host_impl->pending_tree()->LayerById(layer_->id());
+ EXPECT_VECTOR2DF_EQ(gfx::ScrollOffset(500.f, 550.f),
+ layer_impl->CurrentScrollOffset());
+ completion_.Signal();
+ EndTest();
+ }
+
+ private:
+ CompletionEvent completion_;
+};
+
+MULTI_THREAD_TEST_F(ImplSideInvalidationWithoutCommitTestScroll);
+
class LayerTreeHostAnimationTestNotifyAnimationFinished
: public LayerTreeHostAnimationTest {
public:
diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc
index 9c7de670edb..024ca0204ab 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_context.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc
@@ -5,7 +5,6 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "cc/layers/heads_up_display_layer.h"
#include "cc/layers/layer_impl.h"
diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 2f3eeacef91..edc62a8e36a 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -5,7 +5,6 @@
#include <stddef.h>
#include "base/location.h"
-#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/layers/effect_tree_layer_list_iterator.h"
@@ -190,6 +189,36 @@ TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
}
TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+ SkiaRenderer_RunSingleThread) {
+ use_gl_renderer_ = true;
+ use_skia_renderer_ = true;
+ RunTest(CompositorMode::SINGLE_THREADED);
+}
+
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+ SkiaRenderer_RunMultiThread) {
+ use_gl_renderer_ = true;
+ use_skia_renderer_ = true;
+ RunTest(CompositorMode::THREADED);
+}
+
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+ SkiaRenderer_RunSingleThread_OutOfOrderCallbacks) {
+ use_gl_renderer_ = true;
+ use_skia_renderer_ = true;
+ out_of_order_callbacks_ = true;
+ RunTest(CompositorMode::SINGLE_THREADED);
+}
+
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
+ SkiaRenderer_RunMultiThread_OutOfOrderCallbacks) {
+ use_gl_renderer_ = true;
+ use_skia_renderer_ = true;
+ out_of_order_callbacks_ = true;
+ RunTest(CompositorMode::THREADED);
+}
+
+TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
SoftwareRenderer_RunSingleThread) {
use_gl_renderer_ = false;
RunTest(CompositorMode::SINGLE_THREADED);
diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
index babaa05fef3..68982f6f0cf 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -5,7 +5,6 @@
#include "cc/trees/layer_tree_host.h"
#include "base/location.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index 539192d8884..fa670feff83 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -505,9 +505,33 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->has_ever_been_drawn_ = false;
// Note: this needs to happen after SetPropertyTrees.
+ target_tree->HandleTickmarksVisibilityChange();
target_tree->HandleScrollbarShowRequestsFromMain();
}
+void LayerTreeImpl::HandleTickmarksVisibilityChange() {
+ if (!host_impl_->ViewportMainScrollLayer())
+ return;
+
+ ScrollbarAnimationController* controller =
+ host_impl_->ScrollbarAnimationControllerForElementId(
+ OuterViewportScrollLayer()->element_id());
+
+ if (!controller)
+ return;
+
+ for (ScrollbarLayerImplBase* scrollbar : controller->Scrollbars()) {
+ if (scrollbar->orientation() != VERTICAL)
+ continue;
+
+ // Android Overlay Scrollbar don't have FindInPage Tickmarks.
+ if (scrollbar->GetScrollbarAnimator() != LayerTreeSettings::AURA_OVERLAY)
+ DCHECK(!scrollbar->HasFindInPageTickmarks());
+
+ controller->UpdateTickmarksVisibility(scrollbar->HasFindInPageTickmarks());
+ }
+}
+
void LayerTreeImpl::HandleScrollbarShowRequestsFromMain() {
LayerTreeHostCommon::CallFunctionForEveryLayer(this, [this](
LayerImpl* layer) {
@@ -553,6 +577,14 @@ LayerImplList::const_iterator LayerTreeImpl::end() const {
return layer_list_.cend();
}
+LayerImplList::const_reverse_iterator LayerTreeImpl::rbegin() const {
+ return layer_list_.crbegin();
+}
+
+LayerImplList::const_reverse_iterator LayerTreeImpl::rend() const {
+ return layer_list_.crend();
+}
+
LayerImplList::reverse_iterator LayerTreeImpl::rbegin() {
return layer_list_.rbegin();
}
@@ -1340,6 +1372,10 @@ TaskRunnerProvider* LayerTreeImpl::task_runner_provider() const {
return host_impl_->task_runner_provider();
}
+LayerTreeFrameSink* LayerTreeImpl::layer_tree_frame_sink() {
+ return host_impl_->layer_tree_frame_sink();
+}
+
const LayerTreeSettings& LayerTreeImpl::settings() const {
return host_impl_->settings();
}
@@ -1384,6 +1420,10 @@ gfx::Size LayerTreeImpl::device_viewport_size() const {
return host_impl_->device_viewport_size();
}
+gfx::Rect LayerTreeImpl::viewport_visible_rect() const {
+ return host_impl_->viewport_visible_rect();
+}
+
DebugRectHistory* LayerTreeImpl::debug_rect_history() const {
return host_impl_->debug_rect_history();
}
@@ -1593,11 +1633,13 @@ void LayerTreeImpl::AppendSwapPromises(
new_swap_promises.clear();
}
-void LayerTreeImpl::FinishSwapPromises(viz::CompositorFrameMetadata* metadata) {
+void LayerTreeImpl::FinishSwapPromises(
+ viz::CompositorFrameMetadata* metadata,
+ FrameTokenAllocator* frame_token_allocator) {
for (const auto& swap_promise : swap_promise_list_)
- swap_promise->WillSwap(metadata);
+ swap_promise->WillSwap(metadata, frame_token_allocator);
for (const auto& swap_promise : pinned_swap_promise_list_)
- swap_promise->WillSwap(metadata);
+ swap_promise->WillSwap(metadata, frame_token_allocator);
}
void LayerTreeImpl::ClearSwapPromises() {
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index 4352049dd43..62c31dbd0a1 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -12,7 +12,6 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/values.h"
#include "cc/base/synced_property.h"
#include "cc/input/event_listener_properties.h"
@@ -44,6 +43,7 @@ class HeadsUpDisplayLayerImpl;
class ImageDecodeCache;
class LayerTreeDebugState;
class LayerTreeImpl;
+class LayerTreeFrameSink;
class LayerTreeResourceProvider;
class LayerTreeSettings;
class MemoryHistory;
@@ -105,6 +105,7 @@ class CC_EXPORT LayerTreeImpl {
// Methods called by the layer tree that pass-through or access LTHI.
// ---------------------------------------------------------------------------
+ LayerTreeFrameSink* layer_tree_frame_sink();
const LayerTreeSettings& settings() const;
const LayerTreeDebugState& debug_state() const;
viz::ContextProvider* context_provider() const;
@@ -116,6 +117,7 @@ class CC_EXPORT LayerTreeImpl {
FrameRateCounter* frame_rate_counter() const;
MemoryHistory* memory_history() const;
gfx::Size device_viewport_size() const;
+ gfx::Rect viewport_visible_rect() const;
DebugRectHistory* debug_rect_history() const;
bool IsActiveTree() const;
bool IsPendingTree() const;
@@ -185,6 +187,8 @@ class CC_EXPORT LayerTreeImpl {
LayerImplList::const_iterator begin() const;
LayerImplList::const_iterator end() const;
+ LayerImplList::const_reverse_iterator rbegin() const;
+ LayerImplList::const_reverse_iterator rend() const;
LayerImplList::reverse_iterator rbegin();
LayerImplList::reverse_iterator rend();
@@ -446,7 +450,8 @@ 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);
+ void FinishSwapPromises(viz::CompositorFrameMetadata* metadata,
+ FrameTokenAllocator* frame_token_allocator);
void ClearSwapPromises();
void BreakSwapPromises(SwapPromise::DidNotSwapReason reason);
@@ -550,6 +555,8 @@ class CC_EXPORT LayerTreeImpl {
void ClearLayerList();
void BuildLayerListForTesting();
+
+ void HandleTickmarksVisibilityChange();
void HandleScrollbarShowRequestsFromMain();
void InvalidateRegionForImages(
diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc
index 36c37b3b8b0..3856dcd0c42 100644
--- a/chromium/cc/trees/layer_tree_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_impl_unittest.cc
@@ -5,7 +5,6 @@
#include "cc/trees/layer_tree_impl.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
@@ -2286,7 +2285,9 @@ class PersistentSwapPromise
~PersistentSwapPromise() override = default;
void DidActivate() override {}
- MOCK_METHOD1(WillSwap, void(viz::CompositorFrameMetadata* metadata));
+ MOCK_METHOD2(WillSwap,
+ void(viz::CompositorFrameMetadata* metadata,
+ FrameTokenAllocator* frame_token_allocator));
MOCK_METHOD0(DidSwap, void());
DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
@@ -2305,7 +2306,8 @@ class NotPersistentSwapPromise
~NotPersistentSwapPromise() override = default;
void DidActivate() override {}
- void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
+ void WillSwap(viz::CompositorFrameMetadata* metadata,
+ FrameTokenAllocator* frame_token_allocator) override {}
void DidSwap() override {}
DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
@@ -2343,9 +2345,9 @@ TEST_F(LayerTreeImplTest, PersistentSwapPromisesAreKeptAlive) {
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::_));
+ EXPECT_CALL(*persistent_promises[i], WillSwap(testing::_, testing::_));
}
- host_impl().active_tree()->FinishSwapPromises(nullptr);
+ host_impl().active_tree()->FinishSwapPromises(nullptr, nullptr);
}
TEST_F(LayerTreeImplTest, NotPersistentSwapPromisesAreDroppedWhenSwapFails) {
diff --git a/chromium/cc/trees/layer_tree_settings.cc b/chromium/cc/trees/layer_tree_settings.cc
index a353e68e1f9..08137e0e846 100644
--- a/chromium/cc/trees/layer_tree_settings.cc
+++ b/chromium/cc/trees/layer_tree_settings.cc
@@ -44,7 +44,6 @@ TileManagerSettings LayerTreeSettings::ToTileManagerSettings() const {
tile_manager_settings.use_partial_raster = use_partial_raster;
tile_manager_settings.enable_checker_imaging = enable_checker_imaging;
tile_manager_settings.min_image_bytes_to_checker = min_image_bytes_to_checker;
- tile_manager_settings.enable_image_animations = enable_image_animations;
return tile_manager_settings;
}
diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h
index c9ad35f47e6..2584543f863 100644
--- a/chromium/cc/trees/layer_tree_settings.h
+++ b/chromium/cc/trees/layer_tree_settings.h
@@ -42,7 +42,6 @@ class CC_EXPORT LayerTreeSettings {
int damaged_frame_limit = 3;
bool enable_latency_recovery = true;
bool can_use_lcd_text = true;
- bool use_distance_field_text = false;
bool gpu_rasterization_forced = false;
int gpu_rasterization_msaa_sample_count = 0;
float gpu_rasterization_skewport_target_time_in_seconds = 0.2f;
@@ -71,6 +70,9 @@ class CC_EXPORT LayerTreeSettings {
double background_animation_rate = 1.0;
gfx::Size default_tile_size;
gfx::Size max_untiled_layer_size;
+ // If set, indicates the largest tile size we will use for GPU Raster. If not
+ // set, no limit is enforced.
+ gfx::Size max_gpu_raster_tile_size;
gfx::Size minimum_occlusion_tracking_size;
// 3000 pixels should give sufficient area for prepainting.
// Note this value is specified with an ideal contents scale in mind. That
@@ -92,6 +94,7 @@ class CC_EXPORT LayerTreeSettings {
size_t decoded_image_working_set_budget_bytes = 128 * 1024 * 1024;
int max_preraster_distance_in_screen_pixels = 1000;
viz::ResourceFormat preferred_tile_format;
+ bool unpremultiply_and_dither_low_bit_depth_tiles = false;
bool enable_mask_tiling = true;
@@ -139,8 +142,9 @@ class CC_EXPORT LayerTreeSettings {
// would have been used, out of process gpu raster will be used instead.
bool enable_oop_rasterization = false;
- // Whether images should be animated in the compositor.
- bool enable_image_animations = false;
+ // Whether image animations can be reset to the beginning to avoid skipping
+ // many frames.
+ bool enable_image_animation_resync = true;
// Whether to use edge anti-aliasing for all layer types that supports it.
bool enable_edge_anti_aliasing = true;
diff --git a/chromium/cc/trees/mutator_host.h b/chromium/cc/trees/mutator_host.h
index 7594181d37d..e4aae914bae 100644
--- a/chromium/cc/trees/mutator_host.h
+++ b/chromium/cc/trees/mutator_host.h
@@ -8,7 +8,6 @@
#include <memory>
#include "base/callback_forward.h"
-#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "cc/trees/element_id.h"
#include "cc/trees/layer_tree_mutator.h"
diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc
index afc24f39167..4aface2581b 100644
--- a/chromium/cc/trees/property_tree_builder.cc
+++ b/chromium/cc/trees/property_tree_builder.cc
@@ -9,7 +9,6 @@
#include <map>
#include <set>
-#include "base/memory/ptr_util.h"
#include "cc/base/math_util.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc
index d81a1c10e77..4c4cdd4c632 100644
--- a/chromium/cc/trees/proxy_impl.cc
+++ b/chromium/cc/trees/proxy_impl.cc
@@ -10,7 +10,6 @@
#include <string>
#include "base/auto_reset.h"
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/base/devtools_instrumentation.h"
diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc
index 7de104c60d8..7b7589167bb 100644
--- a/chromium/cc/trees/proxy_main.cc
+++ b/chromium/cc/trees/proxy_main.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include <string>
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/base/completion_event.h"
diff --git a/chromium/cc/trees/render_frame_metadata.cc b/chromium/cc/trees/render_frame_metadata.cc
index d20da91fd15..4466cb928c1 100644
--- a/chromium/cc/trees/render_frame_metadata.cc
+++ b/chromium/cc/trees/render_frame_metadata.cc
@@ -15,6 +15,15 @@ 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;
+}
+
RenderFrameMetadata& RenderFrameMetadata::operator=(
const RenderFrameMetadata&) = default;
@@ -22,7 +31,10 @@ RenderFrameMetadata& RenderFrameMetadata::operator=(
RenderFrameMetadata&& other) = default;
bool RenderFrameMetadata::operator==(const RenderFrameMetadata& other) {
- return root_scroll_offset == other.root_scroll_offset;
+ return root_scroll_offset == other.root_scroll_offset &&
+ root_background_color == other.root_background_color &&
+ is_scroll_offset_at_top == other.is_scroll_offset_at_top &&
+ selection == other.selection;
}
bool RenderFrameMetadata::operator!=(const RenderFrameMetadata& other) {
diff --git a/chromium/cc/trees/render_frame_metadata.h b/chromium/cc/trees/render_frame_metadata.h
index 3c029591724..0a20fa8d73c 100644
--- a/chromium/cc/trees/render_frame_metadata.h
+++ b/chromium/cc/trees/render_frame_metadata.h
@@ -5,8 +5,12 @@
#ifndef CC_TREES_RENDER_FRAME_METADATA_H_
#define CC_TREES_RENDER_FRAME_METADATA_H_
+#include "base/optional.h"
#include "cc/cc_export.h"
+#include "components/viz/common/quads/selection.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/selection_bound.h"
namespace cc {
@@ -17,14 +21,33 @@ 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);
bool operator!=(const RenderFrameMetadata& other);
- // Scroll offset and scale of the root layer. This can be used for tasks
- // like positioning windowed plugins.
- gfx::Vector2dF root_scroll_offset;
+ // Indicates whether the scroll offset of the root layer is at top, i.e.,
+ // whether scroll_offset.y() == 0.
+ bool is_scroll_offset_at_top = true;
+
+ // The background color of a CompositorFrame. It can be used for filling the
+ // content area if the primary surface is unavailable and fallback is not
+ // specified.
+ SkColor root_background_color = SK_ColorWHITE;
+
+ // Scroll offset of the root layer. This optional parameter is only valid
+ // during tests.
+ base::Optional<gfx::Vector2dF> root_scroll_offset;
+
+ // Selection region relative to the current viewport. If the selection is
+ // empty or otherwise unused, the bound types will indicate such.
+ viz::Selection<gfx::SelectionBound> selection;
};
} // namespace cc
diff --git a/chromium/cc/trees/render_frame_metadata_observer.h b/chromium/cc/trees/render_frame_metadata_observer.h
index f1055ec1a7d..90491d70ab9 100644
--- a/chromium/cc/trees/render_frame_metadata_observer.h
+++ b/chromium/cc/trees/render_frame_metadata_observer.h
@@ -11,6 +11,8 @@
namespace cc {
+class FrameTokenAllocator;
+
// Observes RenderFrameMetadata associated with the submission of a frame.
// LayerTreeHostImpl will create the metadata when submitting a CompositorFrame.
//
@@ -22,11 +24,12 @@ class CC_EXPORT RenderFrameMetadataObserver {
// Binds on the current thread. This should only be called from the compositor
// thread.
- virtual void BindToCurrentThread() = 0;
+ virtual void BindToCurrentThread(
+ FrameTokenAllocator* frame_token_allocator) = 0;
// Notification of the RendarFrameMetadata for the frame being submitted to
// the display compositor.
- virtual void OnRenderFrameSubmission(const RenderFrameMetadata& metadata) = 0;
+ virtual void OnRenderFrameSubmission(RenderFrameMetadata metadata) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(RenderFrameMetadataObserver);
diff --git a/chromium/cc/trees/swap_promise.h b/chromium/cc/trees/swap_promise.h
index 81ec7cd0e36..c56b07155b3 100644
--- a/chromium/cc/trees/swap_promise.h
+++ b/chromium/cc/trees/swap_promise.h
@@ -12,6 +12,8 @@
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
@@ -61,7 +63,8 @@ class CC_EXPORT SwapPromise {
virtual ~SwapPromise() {}
virtual void DidActivate() = 0;
- virtual void WillSwap(viz::CompositorFrameMetadata* metadata) = 0;
+ virtual void WillSwap(viz::CompositorFrameMetadata* metadata,
+ FrameTokenAllocator* frame_token_allocator) = 0;
virtual void DidSwap() = 0;
// Return |KEEP_ACTIVE| if this promise should remain active (should not be
// broken by the owner).
diff --git a/chromium/cc/trees/swap_promise_manager_unittest.cc b/chromium/cc/trees/swap_promise_manager_unittest.cc
index 59bd0980283..3acf5aa1f4d 100644
--- a/chromium/cc/trees/swap_promise_manager_unittest.cc
+++ b/chromium/cc/trees/swap_promise_manager_unittest.cc
@@ -4,7 +4,6 @@
#include "cc/trees/swap_promise_manager.h"
-#include "base/memory/ptr_util.h"
#include "cc/trees/swap_promise_monitor.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -31,7 +30,8 @@ class MockSwapPromise : public SwapPromise {
~MockSwapPromise() override = default;
void DidActivate() override {}
- void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
+ void WillSwap(viz::CompositorFrameMetadata* metadata,
+ FrameTokenAllocator* frame_token_allocator) override {}
void DidSwap() override {}
DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
return DidNotSwapAction::BREAK_PROMISE;